diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 127e0b7..4c338ae 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -107,15 +107,17 @@ struct mxc_nand_host {
 	struct device		*dev;
 
 	void __iomem		*regs;
-	int			spare_only;
 	int			status_request;
 	int			pagesize_2k;
-	uint16_t		col_addr;
 	struct clk		*clk;
 	int			clk_act;
 	int			irq;
 
 	wait_queue_head_t	irq_waitq;
+
+	uint8_t			*data_buf;
+	unsigned int		buf_start;
+	int			spare_len;
 };
 
 /* Define delays in microsec for NAND device operations */
@@ -227,23 +229,11 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
 }
 
 static void send_page(struct mxc_nand_host *host, uint8_t buf_id,
-			int spare_only, unsigned int ops)
+		unsigned int ops)
 {
-	DEBUG(MTD_DEBUG_LEVEL3, "send_page (%d)\n", spare_only);
-
 	/* NANDFC buffer 0 is used for page read/write */
 	writew(buf_id, host->regs + NFC_BUF_ADDR);
 
-	/* Configure spare or page+spare access */
-	if (!host->pagesize_2k) {
-		uint16_t config1 = readw(host->regs + NFC_CONFIG1);
-		if (spare_only)
-			config1 |= NFC_SP_EN;
-		else
-			config1 &= ~(NFC_SP_EN);
-		writew(config1, host->regs + NFC_CONFIG1);
-	}
-
 	writew(ops, host->regs + NFC_CONFIG2);
 
 	/* Wait for operation to complete */
@@ -278,6 +268,7 @@ static void send_read_id(struct mxc_nand_host *host)
 		writeb(readb(main_buf + 8), main_buf + 4);
 		writeb(readb(main_buf + 10), main_buf + 5);
 	}
+	memcpy(host->data_buf, host->regs + MAIN_AREA0, 16);
 }
 
 /* This function requests the NANDFC to perform a read of the
@@ -363,32 +354,14 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
 {
 	struct nand_chip *nand_chip = mtd->priv;
 	struct mxc_nand_host *host = nand_chip->priv;
-	uint8_t ret = 0;
-	uint16_t col, rd_word;
-	uint16_t __iomem *main_buf = host->regs + MAIN_AREA0;
-	uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0;
+	uint8_t ret;
 
 	/* Check for status request */
 	if (host->status_request)
 		return get_dev_status(host) & 0xFF;
 
-	/* Get column for 16-bit access */
-	col = host->col_addr >> 1;
-
-	/* If we are accessing the spare region */
-	if (host->spare_only)
-		rd_word = readw(&spare_buf[col]);
-	else
-		rd_word = readw(&main_buf[col]);
-
-	/* Pick upper/lower byte of word from RAM buffer */
-	if (host->col_addr & 0x1)
-		ret = (rd_word >> 8) & 0xFF;
-	else
-		ret = rd_word & 0xFF;
-
-	/* Update saved column address */
-	host->col_addr++;
+	ret = *(uint8_t *)(host->data_buf + host->buf_start);
+	host->buf_start++;
 
 	return ret;
 }
@@ -397,33 +370,10 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
 {
 	struct nand_chip *nand_chip = mtd->priv;
 	struct mxc_nand_host *host = nand_chip->priv;
-	uint16_t col, rd_word, ret;
-	uint16_t __iomem *p;
+	uint16_t ret;
 
-	DEBUG(MTD_DEBUG_LEVEL3,
-	      "mxc_nand_read_word(col = %d)\n", host->col_addr);
-
-	col = host->col_addr;
-	/* Adjust saved column address */
-	if (col < mtd->writesize && host->spare_only)
-		col += mtd->writesize;
-
-	if (col < mtd->writesize)
-		p = (host->regs + MAIN_AREA0) + (col >> 1);
-	else
-		p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1);
-
-	if (col & 1) {
-		rd_word = readw(p);
-		ret = (rd_word >> 8) & 0xff;
-		rd_word = readw(&p[1]);
-		ret |= (rd_word << 8) & 0xff00;
-
-	} else
-		ret = readw(p);
-
-	/* Update saved column address */
-	host->col_addr = col + 2;
+	ret = *(uint16_t *)(host->data_buf + host->buf_start);
+	host->buf_start += 2;
 
 	return ret;
 }
@@ -436,94 +386,14 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
 {
 	struct nand_chip *nand_chip = mtd->priv;
 	struct mxc_nand_host *host = nand_chip->priv;
-	int n, col, i = 0;
-
-	DEBUG(MTD_DEBUG_LEVEL3,
-	      "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr,
-	      len);
-
-	col = host->col_addr;
-
-	/* Adjust saved column address */
-	if (col < mtd->writesize && host->spare_only)
-		col += mtd->writesize;
-
-	n = mtd->writesize + mtd->oobsize - col;
-	n = min(len, n);
-
-	DEBUG(MTD_DEBUG_LEVEL3,
-	      "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n);
-
-	while (n) {
-		void __iomem *p;
-
-		if (col < mtd->writesize)
-			p = host->regs + MAIN_AREA0 + (col & ~3);
-		else
-			p = host->regs + SPARE_AREA0 -
-						mtd->writesize + (col & ~3);
-
-		DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__,
-		      __LINE__, p);
-
-		if (((col | (int)&buf[i]) & 3) || n < 16) {
-			uint32_t data = 0;
-
-			if (col & 3 || n < 4)
-				data = readl(p);
-
-			switch (col & 3) {
-			case 0:
-				if (n) {
-					data = (data & 0xffffff00) |
-					    (buf[i++] << 0);
-					n--;
-					col++;
-				}
-			case 1:
-				if (n) {
-					data = (data & 0xffff00ff) |
-					    (buf[i++] << 8);
-					n--;
-					col++;
-				}
-			case 2:
-				if (n) {
-					data = (data & 0xff00ffff) |
-					    (buf[i++] << 16);
-					n--;
-					col++;
-				}
-			case 3:
-				if (n) {
-					data = (data & 0x00ffffff) |
-					    (buf[i++] << 24);
-					n--;
-					col++;
-				}
-			}
-
-			writel(data, p);
-		} else {
-			int m = mtd->writesize - col;
+	u16 col = host->buf_start;
+	int n = mtd->oobsize + mtd->writesize - col;
 
-			if (col >= mtd->writesize)
-				m += mtd->oobsize;
+	n = min(n, len);
 
-			m = min(n, m) & ~3;
+	memcpy(host->data_buf + col, buf, n);
 
-			DEBUG(MTD_DEBUG_LEVEL3,
-			      "%s:%d: n = %d, m = %d, i = %d, col = %d\n",
-			      __func__,  __LINE__, n, m, i, col);
-
-			memcpy(p, &buf[i], m);
-			col += m;
-			i += m;
-			n -= m;
-		}
-	}
-	/* Update saved column address */
-	host->col_addr = col;
+	host->buf_start += n;
 }
 
 /* Read the data buffer from the NAND Flash. To read the data from NAND
@@ -534,75 +404,14 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
 	struct nand_chip *nand_chip = mtd->priv;
 	struct mxc_nand_host *host = nand_chip->priv;
-	int n, col, i = 0;
+	u16 col = host->buf_start;
+	int n = mtd->oobsize + mtd->writesize - col;
 
-	DEBUG(MTD_DEBUG_LEVEL3,
-	      "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len);
-
-	col = host->col_addr;
-
-	/* Adjust saved column address */
-	if (col < mtd->writesize && host->spare_only)
-		col += mtd->writesize;
-
-	n = mtd->writesize + mtd->oobsize - col;
-	n = min(len, n);
-
-	while (n) {
-		void __iomem *p;
-
-		if (col < mtd->writesize)
-			p = host->regs + MAIN_AREA0 + (col & ~3);
-		else
-			p = host->regs + SPARE_AREA0 -
-					mtd->writesize + (col & ~3);
-
-		if (((col | (int)&buf[i]) & 3) || n < 16) {
-			uint32_t data;
-
-			data = readl(p);
-			switch (col & 3) {
-			case 0:
-				if (n) {
-					buf[i++] = (uint8_t) (data);
-					n--;
-					col++;
-				}
-			case 1:
-				if (n) {
-					buf[i++] = (uint8_t) (data >> 8);
-					n--;
-					col++;
-				}
-			case 2:
-				if (n) {
-					buf[i++] = (uint8_t) (data >> 16);
-					n--;
-					col++;
-				}
-			case 3:
-				if (n) {
-					buf[i++] = (uint8_t) (data >> 24);
-					n--;
-					col++;
-				}
-			}
-		} else {
-			int m = mtd->writesize - col;
+	n = min(n, len);
 
-			if (col >= mtd->writesize)
-				m += mtd->oobsize;
-
-			m = min(n, m) & ~3;
-			memcpy(&buf[i], p, m);
-			col += m;
-			i += m;
-			n -= m;
-		}
-	}
-	/* Update saved column address */
-	host->col_addr = col;
+	memcpy(buf, host->data_buf + col, len);
 
+	host->buf_start += len;
 }
 
 /* Used by the upper layer to verify the data in NAND Flash
@@ -641,6 +450,36 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
 	}
 }
 
+/*
+ * Function to transfer data to/from spare area.
+ */
+static void copy_spare(struct mtd_info *mtd, bool bfrom)
+{
+	struct nand_chip *this = mtd->priv;
+	struct mxc_nand_host *host = this->priv;
+	u16 i, j;
+	u16 n = mtd->writesize >> 9;
+	u8 *d = host->data_buf + mtd->writesize;
+	u8 *s = host->regs + SPARE_AREA0;
+	u16 t = host->spare_len;
+
+	j = (mtd->oobsize / n >> 1) << 1;
+
+	if (bfrom) {
+		for (i = 0; i < n - 1; i++)
+			memcpy(d + i * j, s + i * t, j);
+
+		/* the last section */
+		memcpy(d + i * j, s + i * t, mtd->oobsize - i * j);
+	} else {
+		for (i = 0; i < n - 1; i++)
+			memcpy(&s[i * t], &d[i * j], j);
+
+		/* the last section */
+		memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j);
+	}
+}
+
 static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
 {
 	struct nand_chip *nand_chip = mtd->priv;
@@ -707,19 +546,18 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
 	switch (command) {
 
 	case NAND_CMD_STATUS:
-		host->col_addr = 0;
+		host->buf_start = 0;
 		host->status_request = true;
 		break;
 
 	case NAND_CMD_READ0:
-		host->col_addr = column;
-		host->spare_only = false;
+		host->buf_start = column;
 		useirq = false;
 		break;
 
 	case NAND_CMD_READOOB:
-		host->col_addr = column;
-		host->spare_only = true;
+		host->buf_start = column + mtd->writesize;
+
 		useirq = false;
 		if (host->pagesize_2k)
 			command = NAND_CMD_READ0; /* only READ0 is valid */
@@ -739,15 +577,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
 				mxc_nand_command(mtd, NAND_CMD_READ0, 0,
 						page_addr);
 
-			host->col_addr = column - mtd->writesize;
-			host->spare_only = true;
+			host->buf_start = column;
 
 			/* Set program pointer to spare region */
 			if (!host->pagesize_2k)
 				send_cmd(host, NAND_CMD_READOOB, false);
 		} else {
-			host->spare_only = false;
-			host->col_addr = column;
+			host->buf_start = column;
 
 			/* Set program pointer to page start */
 			if (!host->pagesize_2k)
@@ -757,13 +593,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
 		break;
 
 	case NAND_CMD_PAGEPROG:
-		send_page(host, 0, host->spare_only, NFC_INPUT);
+		memcpy(host->regs + MAIN_AREA0, host->data_buf, mtd->writesize);
+		copy_spare(mtd, false);
+		send_page(host, 0, NFC_INPUT);
 
 		if (host->pagesize_2k) {
 			/* data in 4 areas datas */
-			send_page(host, 1, host->spare_only, NFC_INPUT);
-			send_page(host, 2, host->spare_only, NFC_INPUT);
-			send_page(host, 3, host->spare_only, NFC_INPUT);
+			send_page(host, 1, NFC_INPUT);
+			send_page(host, 2, NFC_INPUT);
+			send_page(host, 3, NFC_INPUT);
 		}
 
 		break;
@@ -789,16 +627,18 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
 			/* send read confirm command */
 			send_cmd(host, NAND_CMD_READSTART, true);
 			/* read for each AREA */
-			send_page(host, 0, host->spare_only, NFC_OUTPUT);
-			send_page(host, 1, host->spare_only, NFC_OUTPUT);
-			send_page(host, 2, host->spare_only, NFC_OUTPUT);
-			send_page(host, 3, host->spare_only, NFC_OUTPUT);
+			send_page(host, 0, NFC_OUTPUT);
+			send_page(host, 1, NFC_OUTPUT);
+			send_page(host, 2, NFC_OUTPUT);
+			send_page(host, 3, NFC_OUTPUT);
 		} else
-			send_page(host, 0, host->spare_only, NFC_OUTPUT);
+			send_page(host, 0, NFC_OUTPUT);
+
+		memcpy(host->data_buf, host->regs + MAIN_AREA0, mtd->writesize);
+		copy_spare(mtd, true);
 		break;
 
 	case NAND_CMD_READID:
-		host->col_addr = 0;
 		send_read_id(host);
 		break;
 
@@ -824,10 +664,14 @@ static int __init mxcnd_probe(struct platform_device *pdev)
 	int err = 0, nr_parts = 0;
 
 	/* Allocate memory for MTD device structure and private data */
-	host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL);
+	host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
+			NAND_MAX_OOBSIZE, GFP_KERNEL);
 	if (!host)
 		return -ENOMEM;
 
+	host->data_buf = (uint8_t *)(host + 1);
+	host->spare_len = 16;
+
 	host->dev = &pdev->dev;
 	/* structures must be linked */
 	this = &host->nand;
