Merge "8660: Add support for Ion" into msm-3.0
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 1449e34..b06bb53 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -4696,6 +4696,7 @@
 	.timer = &msm_timer,
 	.init_machine = msm8960_cdp_init,
 	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
 MACHINE_END
 
 MACHINE_START(MSM8930_MTP, "QCT MSM8930 MTP")
@@ -4705,6 +4706,7 @@
 	.timer = &msm_timer,
 	.init_machine = msm8960_cdp_init,
 	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
 MACHINE_END
 
 MACHINE_START(MSM8930_FLUID, "QCT MSM8930 FLUID")
@@ -4714,5 +4716,6 @@
 	.timer = &msm_timer,
 	.init_machine = msm8960_cdp_init,
 	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
 MACHINE_END
 #endif
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index bbe8748..a0c6878 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5223,7 +5223,7 @@
 	CLK_LOOKUP("usb_hsic_p_clk",	usb_hsic_p_clk.c,	NULL),
 
 	CLK_LOOKUP("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL),
-	CLK_LOOKUP("ebi1_clk",		ebi1_adm_clk.c, "msm_dmov"),
+	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     NULL),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, NULL),
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 4e0d3e9..63fc70f 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -213,7 +213,7 @@
 	if (!debugfs_base)
 		return -ENOMEM;
 
-	strncpy(temp, clock->dbg_name, ARRAY_SIZE(temp)-1);
+	strlcpy(temp, clock->dbg_name, ARRAY_SIZE(temp));
 	for (ptr = temp; *ptr; ptr++)
 		*ptr = tolower(*ptr);
 
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index b597fb1..1df3c23 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -336,6 +336,7 @@
 	struct msm_clock *clock;
 	struct msm_clock_percpu_data *clock_state, *gpt_state;
 	unsigned long irq_flags;
+	struct irq_chip *chip;
 
 	clock = clockevent_to_clock(evt);
 	clock_state = &__get_cpu_var(msm_clocks_percpu)[clock->index];
@@ -355,11 +356,9 @@
 		get_cpu_var(msm_active_clock) = clock;
 		put_cpu_var(msm_active_clock);
 		__raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
-		if (irq_get_chip(clock->irq.irq) &&
-		   irq_get_chip(clock->irq.irq)->irq_unmask) {
-			irq_get_chip(clock->irq.irq)->irq_unmask(
-				irq_get_irq_data(clock->irq.irq));
-		}
+		chip = irq_get_chip(clock->irq.irq);
+		if (chip && chip->irq_unmask)
+			chip->irq_unmask(irq_get_irq_data(clock->irq.irq));
 		if (clock != &msm_clocks[MSM_CLOCK_GPT])
 			__raw_writel(TIMER_ENABLE_EN,
 				msm_clocks[MSM_CLOCK_GPT].regbase +
@@ -375,11 +374,9 @@
 			msm_read_timer_count(clock, LOCAL_TIMER) +
 			clock_state->sleep_offset;
 		__raw_writel(0, clock->regbase + TIMER_MATCH_VAL);
-		if (irq_get_chip(clock->irq.irq) &&
-		   irq_get_chip(clock->irq.irq)->irq_mask) {
-			irq_get_chip(clock->irq.irq)->irq_mask(
-				irq_get_irq_data(clock->irq.irq));
-		}
+		chip = irq_get_chip(clock->irq.irq);
+		if (chip && chip->irq_mask)
+			chip->irq_mask(irq_get_irq_data(clock->irq.irq));
 
 		if (!is_smp() || clock != &msm_clocks[MSM_CLOCK_DGT]
 				|| smp_processor_id())
@@ -973,6 +970,7 @@
 {
 	int i;
 	int res;
+	struct irq_chip *chip;
 	struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT];
 	struct msm_clock *gpt = &msm_clocks[MSM_CLOCK_GPT];
 
@@ -1056,8 +1054,9 @@
 			printk(KERN_ERR "msm_timer_init: setup_irq "
 			       "failed for %s\n", cs->name);
 
-		irq_get_chip(clock->irq.irq)->irq_mask(irq_get_irq_data(
-							       clock->irq.irq));
+		chip = irq_get_chip(clock->irq.irq);
+		if (chip && chip->irq_mask)
+			chip->irq_mask(irq_get_irq_data(clock->irq.irq));
 
 		clockevents_register_device(ce);
 	}
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index a09514b..2bf95a0 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -126,6 +126,10 @@
 
 	idx = msm_mctl_out_type_to_inst_index(
 		p_mctl->sync.pcam_sync, msg_type);
+	if (idx < 0) {
+		pr_err("%s Invalid instance. returning\n", __func__);
+		return -EINVAL;
+	}
 	pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
 	vb = msm_mctl_buf_find(p_mctl, pcam_inst,
 		  del_buf, msg_type, fbuf);
@@ -192,27 +196,52 @@
 }
 
 static int msm_mctl_pp_get_phy_addr(
+	struct msm_cam_v4l2_dev_inst *pcam_inst,
 	uint32_t frame_handle,
 	struct msm_pp_frame *pp_frame)
 {
 	struct msm_frame_buffer *vb = NULL;
 	struct videobuf2_contig_pmem *mem;
+	int i, buf_idx = 0;
 
 	vb = (struct msm_frame_buffer *)frame_handle;
-	mem = vb2_plane_cookie(&vb->vidbuf, 0);
+	buf_idx = vb->vidbuf.v4l2_buf.index;
 	memset(pp_frame, 0, sizeof(struct msm_pp_frame));
 	pp_frame->handle = (uint32_t)vb;
 	pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence;
-	pp_frame->image_type = (unsigned short)mem->path;
 	pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp;
-	/* hard coded for now. Will need to expand to MP case */
-	pp_frame->num_planes = 1;
-	pp_frame->sp.addr_offset = mem->addr_offset;
-	pp_frame->sp.phy_addr = videobuf2_to_pmem_contig(&vb->vidbuf, 0);
-	pp_frame->sp.y_off = 0;
-	pp_frame->sp.cbcr_off = mem->offset.sp_off.cbcr_off;
-	pp_frame->sp.length = mem->size;
-	pp_frame->sp.fd = (int)mem->vaddr;
+	/* Get the cookie for 1st plane and store the path.
+	 * Also use this to check the number of planes in
+	 * this buffer.*/
+	mem = vb2_plane_cookie(&vb->vidbuf, 0);
+	pp_frame->image_type = (unsigned short)mem->path;
+	if (mem->buffer_type == VIDEOBUF2_SINGLE_PLANE) {
+		pp_frame->num_planes = 1;
+		pp_frame->sp.addr_offset = mem->addr_offset;
+		pp_frame->sp.phy_addr =
+			videobuf2_to_pmem_contig(&vb->vidbuf, 0);
+		pp_frame->sp.y_off = 0;
+		pp_frame->sp.cbcr_off = mem->offset.sp_off.cbcr_off;
+		pp_frame->sp.length = mem->size;
+		pp_frame->sp.fd = (int)mem->vaddr;
+	} else {
+		pp_frame->num_planes = pcam_inst->plane_info.num_planes;
+		for (i = 0; i < pp_frame->num_planes; i++) {
+			mem = vb2_plane_cookie(&vb->vidbuf, i);
+			pp_frame->mp[i].addr_offset = mem->addr_offset;
+			pp_frame->mp[i].phy_addr =
+				videobuf2_to_pmem_contig(&vb->vidbuf, i);
+			pp_frame->mp[i].data_offset =
+			pcam_inst->buf_offset[buf_idx][i].data_offset;
+			pp_frame->mp[i].fd = (int)mem->vaddr;
+			pp_frame->mp[i].length = mem->size;
+			D("%s frame id %d buffer %d plane %d phy addr 0x%x"
+				" fd %d length %d\n", __func__,
+				pp_frame->frame_id, buf_idx, i,
+				(uint32_t)pp_frame->mp[i].phy_addr,
+				pp_frame->mp[i].fd, pp_frame->mp[i].length);
+		}
+	}
 	return 0;
 }
 
@@ -235,12 +264,38 @@
 	return 0;
 }
 
+static int msm_mctl_pp_path_to_inst_index(struct msm_cam_v4l2_device *pcam,
+					int out_type)
+{
+	int image_mode;
+	switch (out_type) {
+	case OUTPUT_TYPE_P:
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+		break;
+	case OUTPUT_TYPE_V:
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+		break;
+	case OUTPUT_TYPE_S:
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+		break;
+	default:
+		image_mode = -1;
+		break;
+	}
+	if ((image_mode >= 0) && pcam->dev_inst_map[image_mode])
+		return pcam->dev_inst_map[image_mode]->my_index;
+	else
+		return -EINVAL;
+}
+
 int msm_mctl_pp_proc_vpe_cmd(
 	struct msm_cam_media_controller *p_mctl,
 	struct msm_mctl_pp_cmd *pp_cmd)
 {
-	int rc = 0;
+	int rc = 0, idx;
 	void __user *argp = (void __user *)pp_cmd->value;
+	struct msm_cam_v4l2_dev_inst *pcam_inst;
+
 	switch (pp_cmd->id) {
 	case VPE_CMD_INIT:
 	case VPE_CMD_DEINIT:
@@ -422,15 +477,27 @@
 				zoom->pp_frame_cmd.cookie,
 				zoom->pp_frame_cmd.vpe_output_action,
 				zoom->pp_frame_cmd.path);
-
+		idx = msm_mctl_pp_path_to_inst_index(p_mctl->sync.pcam_sync,
+			zoom->pp_frame_cmd.path);
+		if (idx < 0) {
+			pr_err("%s Invalid path, returning\n", __func__);
+			kfree(zoom);
+			return idx;
+		}
+		pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
+		if (!pcam_inst) {
+			pr_err("%s Invalid instance, returning\n", __func__);
+			kfree(zoom);
+			return -EINVAL;
+		}
 		zoom->user_cmd = pp_cmd->id;
-		rc = msm_mctl_pp_get_phy_addr(
+		rc = msm_mctl_pp_get_phy_addr(pcam_inst,
 			zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
 		if (rc) {
 			kfree(zoom);
 			break;
 		}
-		rc = msm_mctl_pp_get_phy_addr(
+		rc = msm_mctl_pp_get_phy_addr(pcam_inst,
 			zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
 		if (rc) {
 			kfree(zoom);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index c1df55e..ab252c9 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -132,6 +132,8 @@
 static void
 msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
 		      u32 c);
+static inline void msmsdcc_delay(struct msmsdcc_host *host);
+
 
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
@@ -207,77 +209,83 @@
  * @host - Pointer to driver's host structure
  *
  */
-static void msmsdcc_soft_reset_and_restore(struct msmsdcc_host *host)
+static void msmsdcc_soft_reset(struct msmsdcc_host *host)
 {
-	if (host->is_sps_mode) {
-		/* Reset DML first */
-		msmsdcc_dml_reset(host);
-		/*
-		 * delay the SPS pipe reset in thread context as
-		 * sps_connect/sps_disconnect APIs can be called
-		 * only from non-atomic context.
-		 */
-		host->sps.pipe_reset_pending = true;
-	}
 	/*
 	 * Reset SDCC controller's DPSM (data path state machine
 	 * and CPSM (command path state machine).
 	 */
-	mb();
 	writel_relaxed(0, host->base + MMCICOMMAND);
+	msmsdcc_delay(host);
 	writel_relaxed(0, host->base + MMCIDATACTRL);
-	mb();
+	msmsdcc_delay(host);
+}
 
-	pr_debug("%s: Applied soft reset to Controller\n",
-			mmc_hostname(host->mmc));
+static void msmsdcc_hard_reset(struct msmsdcc_host *host)
+{
+	int ret;
 
-	if (host->is_sps_mode)
-		msmsdcc_dml_init(host);
+	/* Reset the controller */
+	ret = clk_reset(host->clk, CLK_RESET_ASSERT);
+	if (ret)
+		pr_err("%s: Clock assert failed at %u Hz"
+			" with err %d\n", mmc_hostname(host->mmc),
+				host->clk_rate, ret);
+
+	ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
+	if (ret)
+		pr_err("%s: Clock deassert failed at %u Hz"
+			" with err %d\n", mmc_hostname(host->mmc),
+			host->clk_rate, ret);
+
+	/* Give some delay for clock reset to propogate to controller */
+	msmsdcc_delay(host);
 }
 
 static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
 {
 	if (host->plat->sdcc_v4_sup) {
-		msmsdcc_soft_reset_and_restore(host);
+		if (host->is_sps_mode) {
+			/* Reset DML first */
+			msmsdcc_dml_reset(host);
+			/*
+			 * delay the SPS pipe reset in thread context as
+			 * sps_connect/sps_disconnect APIs can be called
+			 * only from non-atomic context.
+			 */
+			host->sps.pipe_reset_pending = true;
+		}
+		mb();
+		msmsdcc_soft_reset(host);
+
+		pr_debug("%s: Applied soft reset to Controller\n",
+				mmc_hostname(host->mmc));
+
+		if (host->is_sps_mode)
+			msmsdcc_dml_init(host);
 	} else {
 		/* Give Clock reset (hard reset) to controller */
 		u32	mci_clk = 0;
 		u32	mci_mask0 = 0;
-		int ret;
 
 		/* Save the controller state */
 		mci_clk = readl_relaxed(host->base + MMCICLOCK);
 		mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
-
 		mb();
-		/* Reset the controller */
-		ret = clk_reset(host->clk, CLK_RESET_ASSERT);
-		if (ret)
-			pr_err("%s: Clock assert failed at %u Hz"
-				" with err %d\n", mmc_hostname(host->mmc),
-					host->clk_rate, ret);
 
-		ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
-		if (ret)
-			pr_err("%s: Clock deassert failed at %u Hz"
-				" with err %d\n", mmc_hostname(host->mmc),
-					host->clk_rate, ret);
-
+		msmsdcc_hard_reset(host);
 		pr_debug("%s: Controller has been reinitialized\n",
 				mmc_hostname(host->mmc));
 
-		mb();
 		/* Restore the contoller state */
 		writel_relaxed(host->pwr, host->base + MMCIPOWER);
+		msmsdcc_delay(host);
 		writel_relaxed(mci_clk, host->base + MMCICLOCK);
+		msmsdcc_delay(host);
 		writel_relaxed(mci_mask0, host->base + MMCIMASK0);
-		ret = clk_set_rate(host->clk, host->clk_rate);
-		if (ret)
-			pr_err("%s: Failed to set clk rate %u Hz. err %d\n",
-					mmc_hostname(host->mmc),
-					host->clk_rate, ret);
-		mb();
+		mb(); /* no delay required after writing to MASK0 register */
 	}
+
 	if (host->dummy_52_needed)
 		host->dummy_52_needed = 0;
 }
@@ -310,8 +318,6 @@
 	return retval;
 }
 
-static inline void msmsdcc_delay(struct msmsdcc_host *host);
-
 static void
 msmsdcc_stop_data(struct msmsdcc_host *host)
 {
@@ -361,8 +367,13 @@
 msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
 {
 	writel_relaxed(arg, host->base + MMCIARGUMENT);
-	msmsdcc_delay(host);
 	writel_relaxed(c, host->base + MMCICOMMAND);
+	/*
+	 * As after sending the command, we don't write any of the
+	 * controller registers and just wait for the
+	 * CMD_RESPOND_END/CMD_SENT/Command failure notication
+	 * from Controller.
+	 */
 	mb();
 }
 
@@ -374,7 +385,6 @@
 	writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
 	writel_relaxed((unsigned int)host->curr.xfer_size,
 			host->base + MMCIDATALENGTH);
-	msmsdcc_delay(host);	/* Allow data parms to be applied */
 	writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
 	msmsdcc_delay(host);	/* Force delay prior to ADM or command */
 
@@ -931,7 +941,7 @@
 		}
 	}
 
-	if (host->prog_scan && (cmd->opcode == 12)) {
+	if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
 		*c |= MCI_CPSM_PROGENA;
 		host->prog_enable = 1;
 	}
@@ -1013,6 +1023,8 @@
 
 	if (data->flags & MMC_DATA_READ)
 		datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
+	else if (data->flags & MMC_DATA_WRITE)
+		datactrl |= MCI_DATA_PEND;
 
 	clks = (unsigned long long)data->timeout_ns * host->clk_rate;
 	do_div(clks, 1000000000UL);
@@ -1029,8 +1041,6 @@
 		host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
 		host->dma.hdr.user = (void *)host;
 		host->dma.busy = 1;
-		if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
-			host->prog_scan = 1;
 
 		if (cmd) {
 			msmsdcc_start_command_deferred(host, cmd, &c);
@@ -1043,8 +1053,6 @@
 		msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
 	} else {
 		/* SPS-BAM mode or PIO mode */
-		if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
-			host->prog_scan = 1;
 		writel_relaxed(timeout, base + MMCIDATATIMER);
 
 		writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
@@ -1052,8 +1060,14 @@
 		writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
 				(~(MCI_IRQ_PIO))) | pio_irqmask,
 				host->base + MMCIMASK0);
-		msmsdcc_delay(host);	/* Allow parms to be applied */
 		writel_relaxed(datactrl, base + MMCIDATACTRL);
+		/*
+		 * We don't need delay after writing to DATA_CTRL register
+		 * if we are not writing to CMD register immediately after
+		 * this. As we already have delay before sending the
+		 * command, we just need mb() here.
+		 */
+		mb();
 
 		if (cmd) {
 			msmsdcc_delay(host); /* Delay between data/command */
@@ -1239,8 +1253,10 @@
 				(~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
 				host->base + MMCIMASK0);
 		if (!host->curr.xfer_remain) {
-			/* Delay needed (same port was just written) */
-			msmsdcc_delay(host);
+			/*
+			 * back to back write to MASK0 register don't need
+			 * synchronization delay.
+			 */
 			writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
 				(~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
 		}
@@ -1329,16 +1345,12 @@
 		} else { /* host->data == NULL */
 			if (!cmd->error && host->prog_enable) {
 				if (status & MCI_PROGDONE) {
-					host->prog_scan = 0;
 					host->prog_enable = 0;
-					 msmsdcc_request_end(host, cmd->mrq);
+					msmsdcc_request_end(host, cmd->mrq);
 				} else
 					host->curr.cmd = cmd;
 			} else {
-				if (host->prog_enable) {
-					host->prog_scan = 0;
-					host->prog_enable = 0;
-				}
+				host->prog_enable = 0;
 				if (host->dummy_52_needed)
 					host->dummy_52_needed = 0;
 				if (cmd->data && cmd->error)
@@ -1351,9 +1363,6 @@
 			msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
 		else
 			msmsdcc_request_start(host, host->curr.mrq);
-	} else if (cmd->data) {
-		if (!(cmd->data->flags & MMC_DATA_READ))
-			msmsdcc_start_data(host, cmd->data, NULL, 0);
 	}
 }
 
@@ -1560,9 +1569,9 @@
 static void
 msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
 {
-	if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
+	if (mrq->data) {
 		/* Queue/read data, daisy-chain command when data starts */
-		if (mrq->sbc)
+		if (mrq->sbc && (mrq->data->flags & MMC_DATA_READ))
 			msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
 		else
 			msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
@@ -1922,7 +1931,9 @@
 		if (!IS_ERR(host->pclk))
 			clk_enable(host->pclk);
 		clk_enable(host->clk);
+		msmsdcc_delay(host);
 	} else {
+		msmsdcc_delay(host);
 		clk_disable(host->clk);
 		if (!IS_ERR(host->pclk))
 			clk_disable(host->pclk);
@@ -2120,6 +2131,10 @@
 					writel_relaxed(host->mci_irqenable,
 							host->base + MMCIMASK0);
 				}
+			} else {
+				writel_relaxed(host->mci_irqenable,
+						host->base + MMCIMASK0);
+				mb();
 			}
 		}
 		spin_unlock_irqrestore(&host->lock, flags);
@@ -2222,6 +2237,7 @@
 		msmsdcc_setup_pins(host, false);
 		break;
 	case MMC_POWER_UP:
+		/* writing PWR_UP bit is redundant */
 		pwr |= MCI_PWR_UP;
 		if (host->sdcc_irq_disabled) {
 			if (host->plat->cfg_mpm_sdiowakeup)
@@ -2255,7 +2271,7 @@
 	if (host->pwr != pwr) {
 		host->pwr = pwr;
 		writel_relaxed(pwr, host->base + MMCIPOWER);
-		mb();
+		msmsdcc_delay(host);
 	}
 	if (!host->clks_on) {
 		/* force the clocks to be off */
@@ -2279,7 +2295,7 @@
 				writel_relaxed(MCI_SDIOINTMASK,
 						host->base + MMCIMASK0);
 			}
-			msmsdcc_delay(host);
+			mb();
 		}
 		msmsdcc_setup_clocks(host, false);
 		host->clks_on = 0;
@@ -2299,7 +2315,7 @@
 	else
 		clk &= ~MCI_CLK_PWRSAVE;
 	writel_relaxed(clk, host->base + MMCICLOCK);
-	mb();
+	msmsdcc_delay(host);
 
 	return 0;
 }
@@ -2446,7 +2462,7 @@
 	/* Stop SD CLK output. */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
 			MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
-
+	msmsdcc_delay(host);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	/*
@@ -2460,6 +2476,7 @@
 	spin_lock_irqsave(&host->lock, flags);
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
 			IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
+	msmsdcc_delay(host);
 	host->io_pad_pwr_switch = 1;
 	spin_unlock_irqrestore(&host->lock, flags);
 
@@ -2470,6 +2487,7 @@
 	/* Start SD CLK output. */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
 			& ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	msmsdcc_delay(host);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	/*
@@ -2683,6 +2701,7 @@
 	 */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
 			& ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	msmsdcc_delay(host);
 	/* first of all reset the tuning block */
 	rc = msmsdcc_init_cm_sdc4_dll(host);
 	if (rc)
@@ -2757,6 +2776,7 @@
 	/* re-enable PWESAVE */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
 			MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	msmsdcc_delay(host);
 	host->cmd19_tuning_in_progress = 0;
 	return rc;
 }
@@ -3463,10 +3483,7 @@
 					msmsdcc_request_end(host, mrq);
 			}
 		} else {
-			if (host->prog_enable) {
-				host->prog_scan = 0;
-				host->prog_enable = 0;
-			}
+			host->prog_enable = 0;
 			msmsdcc_reset_and_restore(host);
 			msmsdcc_request_end(host, mrq);
 		}
@@ -3678,6 +3695,8 @@
 		      msmsdcc_get_min_sup_clk_rate(host)));
 
 	host->clks_on = 1;
+	/* Apply Hard reset to SDCC to put it in power on default state */
+	msmsdcc_hard_reset(host);
 
 	ret = msmsdcc_vreg_init(host, true);
 	if (ret) {
@@ -3709,6 +3728,7 @@
 	mmc->caps |= plat->mmc_bus_width;
 
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+	mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
 
 	/*
 	 * If we send the CMD23 before multi block write/read command
@@ -3749,8 +3769,6 @@
 	writel_relaxed(0, host->base + MMCIMASK0);
 	writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
 
-	/* Delay needed (MMCIMASK0 was just written above) */
-	msmsdcc_delay(host);
 	writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
 	mb();
 	host->mci_irqenable = MCI_IRQENABLE;
@@ -4143,12 +4161,14 @@
 		 * part of LPM), then clocks should be turned on before
 		 * calling mmc_suspend_host() because mmc_suspend_host might
 		 * send some commands to the card. The clocks will be turned
-		 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
+		 * off again after mmc_suspend_host. Thus for SDIO
 		 * cards, clocks will be turned on before mmc_suspend_host
 		 * and turned off after mmc_suspend_host.
 		 */
-		mmc->ios.clock = host->clk_rate;
-		mmc->ops->set_ios(host->mmc, &host->mmc->ios);
+		if (mmc->card && mmc_card_sdio(mmc->card)) {
+			mmc->ios.clock = host->clk_rate;
+			mmc->ops->set_ios(host->mmc, &host->mmc->ios);
+		}
 
 		/*
 		 * MMC core thinks that host is disabled by now since
@@ -4217,26 +4237,26 @@
 				enable_irq(host->core_irqres->start);
 				host->sdcc_irq_disabled = 0;
 			}
-		}
-		mmc->ios.clock = host->clk_rate;
-		mmc->ops->set_ios(host->mmc, &host->mmc->ios);
+			mmc->ios.clock = host->clk_rate;
+			mmc->ops->set_ios(host->mmc, &host->mmc->ios);
 
-		spin_lock_irqsave(&host->lock, flags);
-		writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
-		mb();
+			spin_lock_irqsave(&host->lock, flags);
+			writel_relaxed(host->mci_irqenable,
+					host->base + MMCIMASK0);
+			mb();
 
-		if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
-				(mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
-				!host->sdio_irq_disabled) {
+			if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
+					!host->sdio_irq_disabled) {
 				if (host->plat->sdiowakeup_irq) {
 					disable_irq_nosync(
 						host->plat->sdiowakeup_irq);
 					msmsdcc_disable_irq_wake(host);
 					host->sdio_irq_disabled = 1;
 				}
-		}
+			}
 
-		spin_unlock_irqrestore(&host->lock, flags);
+			spin_unlock_irqrestore(&host->lock, flags);
+		}
 
 		mmc_resume_host(mmc);
 
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 31ece6e..590c293 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -77,6 +77,7 @@
 #define MCI_DPSM_DIRECTION	(1 << 1)
 #define MCI_DPSM_MODE		(1 << 2)
 #define MCI_DPSM_DMAENABLE	(1 << 3)
+#define MCI_DATA_PEND		(1 << 17)
 #define MCI_AUTO_PROG_DONE	(1 << 19)
 #define MCI_RX_DATA_PEND	(1 << 20)
 
@@ -208,7 +209,7 @@
 
 #define NR_SG		32
 
-#define MSM_MMC_IDLE_TIMEOUT	10000 /* msecs */
+#define MSM_MMC_IDLE_TIMEOUT	5000 /* msecs */
 
 /*
  * Set the request timeout to 10secs to allow
@@ -332,7 +333,6 @@
 
 	struct tasklet_struct 	dma_tlet;
 
-	unsigned int prog_scan;
 	unsigned int prog_enable;
 
 	/* Command parameters */
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 179a4ac..cca1035 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -261,7 +261,8 @@
 
 config ISL9519_CHARGER
 	tristate "isl9519 charger"
-	depends on BATTERY_MSM8X60
+	depends on (BATTERY_MSM8X60 || PM8921_CHARGER)
+	depends on I2C
 	default n
 	help
 	  The isl9519q charger chip from intersil is connected to an external
diff --git a/drivers/power/isl9519q.c b/drivers/power/isl9519q.c
index a45d286..733de45 100644
--- a/drivers/power/isl9519q.c
+++ b/drivers/power/isl9519q.c
@@ -20,9 +20,11 @@
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/msm-charger.h>
+#include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/slab.h>
 #include <linux/i2c/isl9519.h>
 #include <linux/msm_adc.h>
+#include <linux/spinlock.h>
 
 #define CHG_CURRENT_REG		0x14
 #define MAX_SYS_VOLTAGE_REG	0x15
@@ -34,7 +36,7 @@
 
 #define TRCKL_CHG_STATUS_BIT	0x80
 
-#define ISL9519_CHG_PERIOD	((HZ) * 150)
+#define ISL9519_CHG_PERIOD_SEC	150
 
 struct isl9519q_struct {
 	struct i2c_client		*client;
@@ -52,6 +54,10 @@
 	struct msm_hardware_charger	adapter_hw_chg;
 	int				suspended;
 	int				charge_at_resume;
+	struct ext_chg_pm8921		ext_chg;
+	spinlock_t			lock;
+	bool				notify_by_pmic;
+	bool				trickle;
 };
 
 static int isl9519q_read_reg(struct i2c_client *client, int reg,
@@ -70,6 +76,8 @@
 	} else
 		*val = ret;
 
+	pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, *val);
+
 	return 0;
 }
 
@@ -79,6 +87,8 @@
 	int ret;
 	struct isl9519q_struct *isl_chg;
 
+	pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val);
+
 	isl_chg = i2c_get_clientdata(client);
 	ret = i2c_smbus_write_word_data(isl_chg->client, reg, val);
 
@@ -91,6 +101,14 @@
 	return 0;
 }
 
+/**
+ * Read charge-current via ADC.
+ *
+ * The ISL CCMON (charge-current-monitor) pin is connected to
+ * the PMIC MPP#X pin.
+ * This not required when notify_by_pmic is used where the PMIC
+ * uses BMS to notify the ISL on charging-done / charge-resume.
+ */
 static int isl_read_adc(int channel, int *mv_reading)
 {
 	int ret;
@@ -136,98 +154,129 @@
 out:
 	*mv_reading = 0;
 	pr_debug("%s: done with error for %d\n", __func__, channel);
-	return -EINVAL;
 
+	return -EINVAL;
 }
 
-static void isl9519q_charge(struct work_struct *isl9519_work)
+static bool is_trickle_charging(struct isl9519q_struct *isl_chg)
 {
-	u16 temp;
+	u16 ctrl = 0;
 	int ret;
+
+	ret = isl9519q_read_reg(isl_chg->client, CONTROL_REG, &ctrl);
+
+	if (!ret) {
+		pr_debug("%s.control_reg=0x%x.\n", __func__, ctrl);
+	} else {
+		dev_err(&isl_chg->client->dev,
+			"%s couldnt read cntrl reg\n", __func__);
+	}
+
+	if (ctrl & TRCKL_CHG_STATUS_BIT)
+		return true;
+
+	return false;
+}
+
+static void isl_adapter_check_ichg(struct isl9519q_struct *isl_chg)
+{
+	int ichg; /* isl charger current */
+	int mv_reading = 0;
+
+	ichg = isl_read_adc(CHANNEL_ADC_BATT_AMON, &mv_reading);
+
+	dev_dbg(&isl_chg->client->dev, "%s mv_reading=%d\n",
+		__func__, mv_reading);
+	dev_dbg(&isl_chg->client->dev, "%s isl_charger_current=%d\n",
+		__func__, ichg);
+
+	if (ichg >= 0 && ichg <= isl_chg->term_current)
+		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
+					 CHG_DONE_EVENT);
+
+	isl_chg->trickle = is_trickle_charging(isl_chg);
+	if (isl_chg->trickle)
+		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
+					 CHG_BATT_BEGIN_FAST_CHARGING);
+}
+
+/**
+ * isl9519q_worker
+ *
+ * Periodic task required to kick the ISL HW watchdog to keep
+ * charging.
+ *
+ * @isl9519_work: work context.
+ */
+static void isl9519q_worker(struct work_struct *isl9519_work)
+{
 	struct isl9519q_struct *isl_chg;
-	int isl_charger_current;
-	int mv_reading;
 
 	isl_chg = container_of(isl9519_work, struct isl9519q_struct,
 			charge_work.work);
 
 	dev_dbg(&isl_chg->client->dev, "%s\n", __func__);
 
-	if (isl_chg->charging) {
-		isl_charger_current = isl_read_adc(CHANNEL_ADC_BATT_AMON,
-								&mv_reading);
-		dev_dbg(&isl_chg->client->dev, "%s mv_reading=%d\n",
-				__func__, mv_reading);
-		dev_dbg(&isl_chg->client->dev, "%s isl_charger_current=%d\n",
-				__func__, isl_charger_current);
-		if (isl_charger_current >= 0
-			&& isl_charger_current <= isl_chg->term_current) {
-			msm_charger_notify_event(
-					&isl_chg->adapter_hw_chg,
-					CHG_DONE_EVENT);
-		}
-		isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG,
-				isl_chg->chgcurrent);
-		ret = isl9519q_read_reg(isl_chg->client, CONTROL_REG, &temp);
-		if (!ret) {
-			if (!(temp & TRCKL_CHG_STATUS_BIT))
-				msm_charger_notify_event(
-						&isl_chg->adapter_hw_chg,
-						CHG_BATT_BEGIN_FAST_CHARGING);
-		} else {
-			dev_err(&isl_chg->client->dev,
-				"%s couldnt read cntrl reg\n", __func__);
-		}
-		schedule_delayed_work(&isl_chg->charge_work,
-						ISL9519_CHG_PERIOD);
+	if (!isl_chg->charging) {
+		pr_info("%s.stop charging.\n", __func__);
+		isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG, 0);
+		return; /* Stop periodic worker */
 	}
+
+	/* Kick the dog by writting to CHG_CURRENT_REG */
+	isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG,
+			   isl_chg->chgcurrent);
+
+	if (isl_chg->notify_by_pmic)
+		isl_chg->trickle = is_trickle_charging(isl_chg);
+	else
+		isl_adapter_check_ichg(isl_chg);
+
+	schedule_delayed_work(&isl_chg->charge_work,
+			      (ISL9519_CHG_PERIOD_SEC * HZ));
 }
 
-static int isl9519q_start_charging(struct msm_hardware_charger *hw_chg,
-		int chg_voltage, int chg_current)
+static int isl9519q_start_charging(struct isl9519q_struct *isl_chg,
+				   int chg_voltage, int chg_current)
 {
-	struct isl9519q_struct *isl_chg;
 	int ret = 0;
 
-	isl_chg = container_of(hw_chg, struct isl9519q_struct, adapter_hw_chg);
-	if (isl_chg->charging)
-		/* we are already charging */
+	pr_info("%s.\n", __func__);
+
+	if (isl_chg->charging) {
+		pr_warn("%s.already charging.\n", __func__);
 		return 0;
+	}
 
 	if (isl_chg->suspended) {
+		pr_warn("%s.suspended - can't start charging.\n", __func__);
 		isl_chg->charge_at_resume = 1;
 		return 0;
 	}
 
-	dev_dbg(&isl_chg->client->dev, "%s\n", __func__);
+	dev_dbg(&isl_chg->client->dev,
+		"%s starting timed work.period=%d seconds.\n",
+		__func__, (int) ISL9519_CHG_PERIOD_SEC);
 
-	ret = isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG,
-						isl_chg->chgcurrent);
-	if (ret) {
-		dev_err(&isl_chg->client->dev,
-			"%s coulnt write to current_reg\n", __func__);
-		goto out;
-	}
+	/*
+	 * The ISL will start charging from the worker context.
+	 * This API might be called from interrupt context.
+	 */
+	schedule_delayed_work(&isl_chg->charge_work, 1);
 
-	dev_dbg(&isl_chg->client->dev, "%s starting timed work\n",
-							__func__);
-	schedule_delayed_work(&isl_chg->charge_work,
-						ISL9519_CHG_PERIOD);
 	isl_chg->charging = true;
 
-out:
 	return ret;
 }
 
-static int isl9519q_stop_charging(struct msm_hardware_charger *hw_chg)
+static int isl9519q_stop_charging(struct isl9519q_struct *isl_chg)
 {
-	struct isl9519q_struct *isl_chg;
-	int ret = 0;
+	pr_info("%s.\n", __func__);
 
-	isl_chg = container_of(hw_chg, struct isl9519q_struct, adapter_hw_chg);
-	if (!(isl_chg->charging))
-		/* we arent charging */
+	if (!(isl_chg->charging)) {
+		pr_warn("%s.already not charging.\n", __func__);
 		return 0;
+	}
 
 	if (isl_chg->suspended) {
 		isl_chg->charge_at_resume = 0;
@@ -236,17 +285,71 @@
 
 	dev_dbg(&isl_chg->client->dev, "%s\n", __func__);
 
-	ret = isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG, 0);
-	if (ret) {
-		dev_err(&isl_chg->client->dev,
-			"%s coulnt write to current_reg\n", __func__);
-		goto out;
-	}
-
 	isl_chg->charging = false;
-	cancel_delayed_work(&isl_chg->charge_work);
-out:
-	return ret;
+	isl_chg->trickle = false;
+	/*
+	 * The ISL will stop charging from the worker context.
+	 * This API might be called from interrupt context.
+	 */
+	schedule_delayed_work(&isl_chg->charge_work, 1);
+
+	return 0;
+}
+
+static int isl_ext_start_charging(void *ctx)
+{
+	int rc;
+	struct isl9519q_struct *isl_chg = ctx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&isl_chg->lock, flags);
+	rc = isl9519q_start_charging(isl_chg, 0, isl_chg->chgcurrent);
+	spin_unlock_irqrestore(&isl_chg->lock, flags);
+
+	return rc;
+}
+
+static int isl_ext_stop_charging(void *ctx)
+{
+	int rc;
+	struct isl9519q_struct *isl_chg = ctx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&isl_chg->lock, flags);
+	rc = isl9519q_stop_charging(isl_chg);
+	spin_unlock_irqrestore(&isl_chg->lock, flags);
+
+	return rc;
+}
+
+static bool isl_ext_is_trickle(void *ctx)
+{
+	struct isl9519q_struct *isl_chg = ctx;
+
+	return isl_chg->trickle;
+}
+
+static int isl_adapter_start_charging(struct msm_hardware_charger *hw_chg,
+				      int chg_voltage, int chg_current)
+{
+	int rc;
+	struct isl9519q_struct *isl_chg;
+
+	isl_chg = container_of(hw_chg, struct isl9519q_struct, adapter_hw_chg);
+	rc = isl9519q_start_charging(isl_chg, chg_voltage, chg_current);
+
+	return rc;
+}
+
+static int isl_adapter_stop_charging(struct msm_hardware_charger *hw_chg)
+{
+	int rc;
+	struct isl9519q_struct *isl_chg;
+
+	isl_chg = container_of(hw_chg, struct isl9519q_struct, adapter_hw_chg);
+	rc = isl9519q_stop_charging(isl_chg);
+
+	return rc;
 }
 
 static int isl9519q_charging_switched(struct msm_hardware_charger *hw_chg)
@@ -296,6 +399,93 @@
 #define DEFAULT_MAX_VOLTAGE_REG_VALUE	0x1070
 #define DEFAULT_MIN_VOLTAGE_REG_VALUE	0x0D00
 
+static int __devinit isl9519q_init_adapter(struct isl9519q_struct *isl_chg)
+{
+	int ret;
+	struct isl_platform_data *pdata = isl_chg->client->dev.platform_data;
+	struct i2c_client *client = isl_chg->client;
+
+	isl_chg->adapter_hw_chg.type = CHG_TYPE_AC;
+	isl_chg->adapter_hw_chg.rating = 2;
+	isl_chg->adapter_hw_chg.name = "isl-adapter";
+	isl_chg->adapter_hw_chg.start_charging = isl_adapter_start_charging;
+	isl_chg->adapter_hw_chg.stop_charging = isl_adapter_stop_charging;
+	isl_chg->adapter_hw_chg.charging_switched = isl9519q_charging_switched;
+
+	ret = gpio_request(pdata->valid_n_gpio, "isl_charger_valid");
+	if (ret) {
+		dev_err(&client->dev, "%s gpio_request failed "
+				      "for %d ret=%d\n",
+			__func__, pdata->valid_n_gpio, ret);
+		goto out;
+	}
+
+	ret = msm_charger_register(&isl_chg->adapter_hw_chg);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s msm_charger_register failed for ret =%d\n",
+			__func__, ret);
+		goto free_gpio;
+	}
+
+	ret = request_threaded_irq(client->irq, NULL,
+				   isl_valid_handler,
+				   IRQF_TRIGGER_FALLING |
+				   IRQF_TRIGGER_RISING,
+				   "isl_charger_valid", client);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s request_threaded_irq failed "
+			"for %d ret =%d\n",
+			__func__, client->irq, ret);
+		goto unregister;
+	}
+	irq_set_irq_wake(client->irq, 1);
+
+	ret = gpio_get_value_cansleep(isl_chg->valid_n_gpio);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"%s gpio_get_value failed for %d ret=%d\n",
+			__func__, pdata->valid_n_gpio, ret);
+		/* assume absent */
+		ret = 1;
+	}
+	if (!ret) {
+		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
+				CHG_INSERTED_EVENT);
+		isl_chg->present = 1;
+	}
+
+	return 0;
+
+unregister:
+	msm_charger_unregister(&isl_chg->adapter_hw_chg);
+free_gpio:
+	gpio_free(pdata->valid_n_gpio);
+out:
+	return ret;
+
+}
+
+static int __devinit isl9519q_init_ext_chg(struct isl9519q_struct *isl_chg)
+{
+	int ret;
+
+	isl_chg->ext_chg.name = "isl9519q";
+	isl_chg->ext_chg.ctx = isl_chg;
+	isl_chg->ext_chg.start_charging = isl_ext_start_charging;
+	isl_chg->ext_chg.stop_charging = isl_ext_stop_charging;
+	isl_chg->ext_chg.is_trickle = isl_ext_is_trickle;
+	ret = register_external_dc_charger(&isl_chg->ext_chg);
+	if (ret) {
+		pr_err("%s.failed to register external dc charger.ret=%d.\n",
+		       __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int __devinit isl9519q_probe(struct i2c_client *client,
 				    const struct i2c_device_id *id)
 {
@@ -306,6 +496,8 @@
 	ret = 0;
 	pdata = client->dev.platform_data;
 
+	pr_info("%s.\n", __func__);
+
 	if (pdata == NULL) {
 		dev_err(&client->dev, "%s no platform data\n", __func__);
 		ret = -EINVAL;
@@ -324,7 +516,9 @@
 		goto out;
 	}
 
-	INIT_DELAYED_WORK(&isl_chg->charge_work, isl9519q_charge);
+	spin_lock_init(&isl_chg->lock);
+
+	INIT_DELAYED_WORK(&isl_chg->charge_work, isl9519q_worker);
 	isl_chg->client = client;
 	isl_chg->chgcurrent = pdata->chgcurrent;
 	isl_chg->term_current = pdata->term_current;
@@ -337,12 +531,14 @@
 	isl_chg->chgcurrent &= ~0x7F;
 	isl_chg->input_current &= ~0x7F;
 
-	isl_chg->adapter_hw_chg.type = CHG_TYPE_AC;
-	isl_chg->adapter_hw_chg.rating = 2;
-	isl_chg->adapter_hw_chg.name = "isl-adapter";
-	isl_chg->adapter_hw_chg.start_charging = isl9519q_start_charging;
-	isl_chg->adapter_hw_chg.stop_charging = isl9519q_stop_charging;
-	isl_chg->adapter_hw_chg.charging_switched = isl9519q_charging_switched;
+	/**
+	 * ISL is Notified by PMIC to start/stop charging, rather than
+	 * handling interrupt from ISL for End-Of-Chargring, and
+	 * monitoring the charge-current periodically. The valid_n_gpio
+	 * is also not used, dc-present is detected by PMIC.
+	 */
+	isl_chg->notify_by_pmic = (client->irq == 0);
+	i2c_set_clientdata(client, isl_chg);
 
 	if (pdata->chg_detection_config) {
 		ret = pdata->chg_detection_config();
@@ -353,35 +549,6 @@
 		}
 	}
 
-	ret = gpio_request(pdata->valid_n_gpio, "isl_charger_valid");
-	if (ret) {
-		dev_err(&client->dev, "%s gpio_request failed for %d ret=%d\n",
-			__func__, pdata->valid_n_gpio, ret);
-		goto free_isl_chg;
-	}
-
-	i2c_set_clientdata(client, isl_chg);
-
-	ret = msm_charger_register(&isl_chg->adapter_hw_chg);
-	if (ret) {
-		dev_err(&client->dev,
-			"%s msm_charger_register failed for ret =%d\n",
-			__func__, ret);
-		goto free_gpio;
-	}
-
-	ret = request_threaded_irq(client->irq, NULL,
-				   isl_valid_handler,
-				   IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-				   "isl_charger_valid", client);
-	if (ret) {
-		dev_err(&client->dev,
-			"%s request_threaded_irq failed for %d ret =%d\n",
-			__func__, client->irq, ret);
-		goto unregister;
-	}
-	irq_set_irq_wake(client->irq, 1);
-
 	isl_chg->max_system_voltage &= MAX_VOLTAGE_REG_MASK;
 	isl_chg->min_system_voltage &= MIN_VOLTAGE_REG_MASK;
 	if (isl_chg->max_system_voltage == 0)
@@ -391,57 +558,34 @@
 
 	ret = isl9519q_write_reg(isl_chg->client, MAX_SYS_VOLTAGE_REG,
 			isl_chg->max_system_voltage);
-	if (ret) {
-		dev_err(&client->dev,
-			"%s couldnt write to MAX_SYS_VOLTAGE_REG ret=%d\n",
-			__func__, ret);
-		goto free_irq;
-	}
+	if (ret)
+		goto free_isl_chg;
 
 	ret = isl9519q_write_reg(isl_chg->client, MIN_SYS_VOLTAGE_REG,
 			isl_chg->min_system_voltage);
-	if (ret) {
-		dev_err(&client->dev,
-			"%s couldnt write to MIN_SYS_VOLTAGE_REG ret=%d\n",
-			__func__, ret);
-		goto free_irq;
-	}
+	if (ret)
+		goto free_isl_chg;
 
 	if (isl_chg->input_current) {
 		ret = isl9519q_write_reg(isl_chg->client,
 				INPUT_CURRENT_REG,
 				isl_chg->input_current);
-		if (ret) {
-			dev_err(&client->dev,
-				"%s couldnt write INPUT_CURRENT_REG ret=%d\n",
-				__func__, ret);
-			goto free_irq;
-		}
+		if (ret)
+			goto free_isl_chg;
 	}
 
-	ret = gpio_get_value_cansleep(isl_chg->valid_n_gpio);
-	if (ret < 0) {
-		dev_err(&client->dev,
-			"%s gpio_get_value failed for %d ret=%d\n", __func__,
-			pdata->valid_n_gpio, ret);
-		/* assume absent */
-		ret = 1;
-	}
-	if (!ret) {
-		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
-				CHG_INSERTED_EVENT);
-		isl_chg->present = 1;
-	}
+	if (isl_chg->notify_by_pmic)
+		ret = isl9519q_init_ext_chg(isl_chg);
+	else
+		ret = isl9519q_init_adapter(isl_chg);
 
-	pr_debug("%s OK chg_present=%d\n", __func__, isl_chg->present);
+	if (ret)
+		goto free_isl_chg;
+
+	pr_info("%s OK.\n", __func__);
+
 	return 0;
 
-free_irq:
-	free_irq(client->irq, NULL);
-unregister:
-	msm_charger_unregister(&isl_chg->adapter_hw_chg);
-free_gpio:
-	gpio_free(pdata->valid_n_gpio);
 free_isl_chg:
 	kfree(isl_chg);
 out:
@@ -493,7 +637,7 @@
 	isl_chg->suspended  = 0;
 	if (isl_chg->charge_at_resume) {
 		isl_chg->charge_at_resume = 0;
-		isl9519q_start_charging(&isl_chg->adapter_hw_chg, 0, 0);
+		isl9519q_start_charging(isl_chg, 0, 0);
 	}
 	return 0;
 }
@@ -519,10 +663,12 @@
 
 static int __init isl9519q_init(void)
 {
+	pr_info("%s. isl9519q SW rev 1.01\n", __func__);
+
 	return i2c_add_driver(&isl9519q_driver);
 }
 
-module_init(isl9519q_init);
+late_initcall_sync(isl9519q_init);
 
 static void __exit isl9519q_exit(void)
 {
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 06d614b..bc1a25b 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -262,7 +262,10 @@
 		gsbi_resource = platform_get_resource_byname(pdev,
 							     IORESOURCE_MEM,
 							     "gsbi_resource");
-		size = gsbi_resource->end - gsbi_resource->start + 1;
+		if (unlikely(!gsbi_resource))
+			return;
+
+		size = resource_size(gsbi_resource);
 		release_mem_region(gsbi_resource->start, size);
 		iounmap(msm_uport->mapped_gsbi);
 		msm_uport->mapped_gsbi = NULL;
@@ -280,7 +283,7 @@
 						     IORESOURCE_MEM,
 						     "gsbi_resource");
 	if (gsbi_resource) {
-		size = gsbi_resource->end - gsbi_resource->start + 1;
+		size = resource_size(gsbi_resource);
 		if (unlikely(!request_mem_region(gsbi_resource->start, size,
 						 "msm_serial_hs")))
 			return -EBUSY;
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index ad085f9..a7b53e4 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -799,7 +799,6 @@
 	struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
 	struct platform_device *pdev = to_platform_device(port->dev);
 	struct resource *uart_resource;
-	struct resource *gsbi_resource;
 	resource_size_t size;
 
 	uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -815,11 +814,6 @@
 	if (msm_serial_hsl_has_gsbi(port)) {
 		iowrite32(GSBI_PROTOCOL_IDLE, msm_hsl_port->mapped_gsbi +
 			  GSBI_CONTROL_ADDR);
-		gsbi_resource = platform_get_resource_byname(pdev,
-							     IORESOURCE_MEM,
-							     "gsbi_resource");
-
-		size = gsbi_resource->end - gsbi_resource->start + 1;
 		iounmap(msm_hsl_port->mapped_gsbi);
 		msm_hsl_port->mapped_gsbi = NULL;
 	}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 93933f3..5cf79c1 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -555,6 +555,10 @@
 void mdp4_overlay0_done_dsi_video(struct mdp_dma_data *dma)
 {
 	spin_lock(&mdp_spin_lock);
+	if (dsi_pipe->blt_addr == 0) {
+		spin_unlock(&mdp_spin_lock);
+		return;
+	}
 	dma->busy = FALSE;
 	mdp4_dsi_video_blt_dmap_update(dsi_pipe);
 	dsi_pipe->dmap_cnt++;
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index e840230..0eda69a 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -451,6 +451,10 @@
 void mdp4_overlay0_done_lcdc(struct mdp_dma_data *dma)
 {
 	spin_lock(&mdp_spin_lock);
+	if (lcdc_pipe->blt_addr == 0) {
+		spin_unlock(&mdp_spin_lock);
+		return;
+	}
 	dma->busy = FALSE;
 	mdp4_lcdc_blt_dmap_update(lcdc_pipe);
 	lcdc_pipe->dmap_cnt++;
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 99607e7..3d78a13 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -419,6 +419,55 @@
 		spin_unlock(&mdp_spin_lock);
 	}
 #endif
+
+#ifdef CONFIG_FB_MSM_OVERLAY
+	if (isr & INTR_OVERLAY0_DONE) {
+		mdp4_stat.intr_overlay0++;
+		dma = &dma2_data;
+		if (panel & (MDP4_PANEL_LCDC | MDP4_PANEL_DSI_VIDEO)) {
+			/* disable LCDC interrupt */
+			spin_lock(&mdp_spin_lock);
+			mdp_intr_mask &= ~INTR_OVERLAY0_DONE;
+			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+			dma->waiting = FALSE;
+			spin_unlock(&mdp_spin_lock);
+			if (panel & MDP4_PANEL_LCDC)
+				mdp4_overlay0_done_lcdc(dma);
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+			else if (panel & MDP4_PANEL_DSI_VIDEO)
+				mdp4_overlay0_done_dsi_video(dma);
+#endif
+		} else {        /* MDDI, DSI_CMD  */
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+			if (panel & MDP4_PANEL_DSI_CMD)
+				mdp4_overlay0_done_dsi_cmd(dma);
+#else
+			if (panel & MDP4_PANEL_MDDI)
+				mdp4_overlay0_done_mddi(dma);
+#endif
+		}
+		mdp_hw_cursor_done();
+	}
+	if (isr & INTR_OVERLAY1_DONE) {
+		mdp4_stat.intr_overlay1++;
+		/* disable DTV interrupt */
+		dma = &dma_e_data;
+		spin_lock(&mdp_spin_lock);
+		mdp_intr_mask &= ~INTR_OVERLAY1_DONE;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		dma->waiting = FALSE;
+		spin_unlock(&mdp_spin_lock);
+#if defined(CONFIG_FB_MSM_DTV)
+		if (panel & MDP4_PANEL_DTV)
+			mdp4_overlay1_done_dtv();
+#endif
+#if defined(CONFIG_FB_MSM_TVOUT)
+		if (panel & MDP4_PANEL_ATV)
+			mdp4_overlay1_done_atv();
+#endif
+	}
+#endif	/* OVERLAY */
+
 	if (isr & INTR_DMA_P_DONE) {
 		mdp4_stat.intr_dma_p++;
 		dma = &dma2_data;
@@ -488,53 +537,6 @@
 		}
 		spin_unlock(&mdp_spin_lock);
 	}
-#ifdef CONFIG_FB_MSM_OVERLAY
-	if (isr & INTR_OVERLAY0_DONE) {
-		mdp4_stat.intr_overlay0++;
-		dma = &dma2_data;
-		if (panel & (MDP4_PANEL_LCDC | MDP4_PANEL_DSI_VIDEO)) {
-			/* disable LCDC interrupt */
-			spin_lock(&mdp_spin_lock);
-			mdp_intr_mask &= ~INTR_OVERLAY0_DONE;
-			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-			dma->waiting = FALSE;
-			spin_unlock(&mdp_spin_lock);
-			if (panel & MDP4_PANEL_LCDC)
-				mdp4_overlay0_done_lcdc(dma);
-#ifdef CONFIG_FB_MSM_MIPI_DSI
-			else if (panel & MDP4_PANEL_DSI_VIDEO)
-				mdp4_overlay0_done_dsi_video(dma);
-#endif
-		} else {        /* MDDI, DSI_CMD  */
-#ifdef CONFIG_FB_MSM_MIPI_DSI
-			if (panel & MDP4_PANEL_DSI_CMD)
-				mdp4_overlay0_done_dsi_cmd(dma);
-#else
-			if (panel & MDP4_PANEL_MDDI)
-				mdp4_overlay0_done_mddi(dma);
-#endif
-		}
-		mdp_hw_cursor_done();
-	}
-	if (isr & INTR_OVERLAY1_DONE) {
-		mdp4_stat.intr_overlay1++;
-		/* disable DTV interrupt */
-		dma = &dma_e_data;
-		spin_lock(&mdp_spin_lock);
-		mdp_intr_mask &= ~INTR_OVERLAY1_DONE;
-		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-		dma->waiting = FALSE;
-		spin_unlock(&mdp_spin_lock);
-#if defined(CONFIG_FB_MSM_DTV)
-		if (panel & MDP4_PANEL_DTV)
-			mdp4_overlay1_done_dtv();
-#endif
-#if defined(CONFIG_FB_MSM_TVOUT)
-		if (panel & MDP4_PANEL_ATV)
-			mdp4_overlay1_done_atv();
-#endif
-	}
-#endif	/* OVERLAY */
 	if (isr & INTR_DMA_P_HISTOGRAM) {
 		isr = inpdw(MDP_DMA_P_HIST_INTR_STATUS);
 		mask = inpdw(MDP_DMA_P_HIST_INTR_ENABLE);
diff --git a/drivers/video/msm/mipi_chimei_wxga_pt.c b/drivers/video/msm/mipi_chimei_wxga_pt.c
index fe7035a..4729d83 100644
--- a/drivers/video/msm/mipi_chimei_wxga_pt.c
+++ b/drivers/video/msm/mipi_chimei_wxga_pt.c
@@ -168,7 +168,12 @@
 	pinfo->mipi.stream = false; /* dma_p */
 	pinfo->mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE;
 	pinfo->mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
-	pinfo->mipi.fixed_packet_size = 4;
+	/*
+	 * toshiba d2l chip does not need max_pkt_szie dcs cmd
+	 * client reply len is directly configure through
+	 * RDPKTLN register (0x0404)
+	 */
+	pinfo->mipi.no_max_pkt_size = 1;
 	pinfo->mipi.force_clk_lane_hs = 1;
 
 	ret = mipi_tc358764_dsi2lvds_register(pinfo, MIPI_DSI_PRIM,
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 600aac5..8d07e56 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -1159,20 +1159,22 @@
 			struct dsi_buf *tp, struct dsi_buf *rp,
 			struct dsi_cmd_desc *cmds, int rlen)
 {
-	int i , cnt, len, diff, pkt_size;
+	int cnt, len, diff, pkt_size;
 	unsigned long flag;
 	char cmd;
 
+	if (mfd->panel_info.mipi.no_max_pkt_size) {
+		/* Only support rlen = 4*n */
+		rlen += 3;
+		rlen &= 0x03;
+	}
+
 	len = rlen;
 	diff = 0;
 
 	if (len <= 2)
 		cnt = 4;	/* short read */
-	else if (mfd->panel_info.mipi.fixed_packet_size) {
-		len = mfd->panel_info.mipi.fixed_packet_size;
-		pkt_size = len; /* Avoid command to the device */
-		cnt = (len + 6 + 3) & ~0x03; /* Add padding for align */
-	} else {
+	else {
 		if (len > MIPI_DSI_LEN)
 			len = MIPI_DSI_LEN;	/* 8 bytes at most */
 
@@ -1203,7 +1205,7 @@
 	dsi_mdp_busy = TRUE;
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
-	if (!mfd->panel_info.mipi.fixed_packet_size) {
+	if (!mfd->panel_info.mipi.no_max_pkt_size) {
 		/* packet size need to be set at every read */
 		pkt_size = len;
 		max_pktsize[0] = pkt_size;
@@ -1223,10 +1225,15 @@
 	 * at RDBK_DATA register already
 	 */
 	mipi_dsi_buf_init(rp);
-	mipi_dsi_cmd_dma_rx(rp, cnt);
+	if (mfd->panel_info.mipi.no_max_pkt_size) {
+		/*
+		 * expect rlen = n * 4
+		 * short alignement for start addr
+		 */
+		rp->data += 2;
+	}
 
-	for (i = 0; i < cnt ; i++)
-		pr_debug("%s.rp->data[%d]=0x%x.\n", __func__, i, rp->data[i]);
+	mipi_dsi_cmd_dma_rx(rp, cnt);
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
 	dsi_mdp_busy = FALSE;
@@ -1234,12 +1241,16 @@
 	complete(&dsi_mdp_comp);
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
-	/* Remove leading padding zeros if exist */
-	for (i = 0; i < cnt ; i++)
-		if (rp->data[0] == 0)
-			rp->data++;
-		else
-			break;
+	if (mfd->panel_info.mipi.no_max_pkt_size) {
+		/*
+		 * remove extra 2 bytes from previous
+		 * rx transaction at shift register
+		 * which was inserted during copy
+		 * shift registers to rx buffer
+		 * rx payload start from long alignment addr
+		 */
+		rp->data += 2;
+	}
 
 	cmd = rp->data[0];
 	switch (cmd) {
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 4c415b6..16979b1 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -122,7 +122,7 @@
 	char dma_trigger;
 	uint32 dsi_pclk_rate;
 	/* The packet-size should not bet changed */
-	char fixed_packet_size;
+	char no_max_pkt_size;
 	/* Clock required during LP commands */
 	char force_clk_lane_hs;
 	/* Pad width */
diff --git a/mm/slub.c b/mm/slub.c
index 35f351f..adf609e 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -557,10 +557,10 @@
 		memset(p + s->objsize, val, s->inuse - s->objsize);
 }
 
-static u8 *check_bytes(u8 *start, unsigned int value, unsigned int bytes)
+static u8 *check_bytes8(u8 *start, u8 value, unsigned int bytes)
 {
 	while (bytes) {
-		if (*start != (u8)value)
+		if (*start != value)
 			return start;
 		start++;
 		bytes--;
@@ -568,6 +568,38 @@
 	return NULL;
 }
 
+static u8 *check_bytes(u8 *start, u8 value, unsigned int bytes)
+{
+	u64 value64;
+	unsigned int words, prefix;
+
+	if (bytes <= 16)
+		return check_bytes8(start, value, bytes);
+
+	value64 = value | value << 8 | value << 16 | value << 24;
+	value64 = (value64 & 0xffffffff) | value64 << 32;
+	prefix = 8 - ((unsigned long)start) % 8;
+
+	if (prefix) {
+		u8 *r = check_bytes8(start, value, prefix);
+		if (r)
+			return r;
+		start += prefix;
+		bytes -= prefix;
+	}
+
+	words = bytes / 8;
+
+	while (words) {
+		if (*(u64 *)start != value64)
+			return check_bytes8(start, value, 8);
+		start += 8;
+		words--;
+	}
+
+	return check_bytes8(start, value, bytes % 8);
+}
+
 static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
 						void *from, void *to)
 {