diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 60ba007aaabf2c83f902ec6e244337a0c98f0fde..08f837b66f61ad753aba9816df8cabe1b6838ac9 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -113,7 +113,8 @@ int spi_claim_bus(struct spi_slave *slave)
 	writel(0, &ds->regs->lvl);
 
 	/* enable SPI */
-	writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
+	writel((readl(&ds->regs->gcr1) |
+		SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
 
 	return 0;
 }
@@ -131,12 +132,10 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 {
 	struct davinci_spi_slave *ds = to_davinci_spi(slave);
 	unsigned int	len, data1_reg_val = readl(&ds->regs->dat1);
-	int		ret, i;
+	unsigned int	i_cnt = 0, o_cnt = 0, buf_reg_val;
 	const u8	*txp = dout; /* dout can be NULL for read operation */
 	u8		*rxp = din;  /* din can be NULL for write operation */
 
-	ret = 0;
-
 	if (bitlen == 0)
 		/* Finish any previously submitted transfers */
 		goto out;
@@ -159,41 +158,51 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	readl(&ds->regs->buf);
 
 	/* keep writing and reading 1 byte until done */
-	for (i = 0; i < len; i++) {
-		/* wait till TXFULL is asserted */
-		while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK);
-
-		/* write the data */
-		data1_reg_val &= ~0xFFFF;
-		if (txp) {
-			data1_reg_val |= *txp;
-			txp++;
+	while ((i_cnt < len) || (o_cnt < len)) {
+		/* read RX buffer and flags */
+		buf_reg_val = readl(&ds->regs->buf);
+
+		/* if data is available */
+		if ((i_cnt < len) &&
+			(buf_reg_val & SPIBUF_RXEMPTY_MASK) == 0) {
+			/*
+			 * If there is no read buffer simply
+			 * ignore the read character
+			 */
+			if (rxp)
+				*rxp++ = buf_reg_val & 0xFF;
+			/* increment read words count */
+			i_cnt++;
 		}
 
 		/*
-		 * Write to DAT1 is required to keep the serial transfer going.
-		 * We just terminate when we reach the end.
+		 * if the tx buffer is empty and there
+		 * is still data to transmit
 		 */
-		if ((i == (len - 1)) && (flags & SPI_XFER_END)) {
-			/* clear CS hold */
-			writel(data1_reg_val &
-				~(1 << SPIDAT1_CSHOLD_SHIFT), &ds->regs->dat1);
-		} else {
-			/* enable CS hold */
-			data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) |
+		if ((o_cnt < len) &&
+			((buf_reg_val & SPIBUF_TXFULL_MASK) == 0)) {
+			/* write the data */
+			data1_reg_val &= ~0xFFFF;
+			if (txp)
+				data1_reg_val |= *txp++;
+			/*
+			 * Write to DAT1 is required to keep
+			 * the serial transfer going.
+			 * We just terminate when we reach the end.
+			 */
+			if ((o_cnt == (len - 1)) && (flags & SPI_XFER_END)) {
+				/* clear CS hold */
+				writel(data1_reg_val &
+						~(1 << SPIDAT1_CSHOLD_SHIFT),
+						&ds->regs->dat1);
+			} else {
+				/* enable CS hold and write TX register */
+				data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) |
 					(slave->cs << SPIDAT1_CSNR_SHIFT));
-			writel(data1_reg_val, &ds->regs->dat1);
-		}
-
-		/* read the data - wait for data availability */
-		while (readl(&ds->regs->buf) & SPIBUF_RXEMPTY_MASK);
-
-		if (rxp) {
-			*rxp = readl(&ds->regs->buf) & 0xFF;
-			rxp++;
-		} else {
-			/* simply drop the read character */
-			readl(&ds->regs->buf);
+				writel(data1_reg_val, &ds->regs->dat1);
+			}
+			/* increment written words count */
+			o_cnt++;
 		}
 	}
 	return 0;