sf: unify status polling for ready bit

All of the spi flash drivers implement the status register polling for
detecting the device ready state, so unify them all in a new helper
function -- spi_flash_wait_ready.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c
index 8d02169..7827b75 100644
--- a/drivers/mtd/spi/atmel.c
+++ b/drivers/mtd/spi/atmel.c
@@ -113,35 +113,8 @@
 
 static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout)
 {
-	struct spi_slave *spi = flash->spi;
-	unsigned long timebase;
-	int ret;
-	u8 cmd = CMD_AT45_READ_STATUS;
-	u8 status;
-
-	timebase = get_timer(0);
-
-	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
-	if (ret)
-		return -1;
-
-	do {
-		ret = spi_xfer(spi, 8, NULL, &status, 0);
-		if (ret)
-			return -1;
-
-		if (status & AT45_STATUS_READY)
-			break;
-	} while (get_timer(timebase) < timeout);
-
-	/* Deactivate CS */
-	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
-
-	if (status & AT45_STATUS_READY)
-		return 0;
-
-	/* Timed out */
-	return -1;
+	return spi_flash_cmd_poll_bit(flash, timeout,
+		CMD_AT45_READ_STATUS, AT45_STATUS_READY);
 }
 
 /*
diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c
index 02c3bb9..4af1e06 100644
--- a/drivers/mtd/spi/eon.c
+++ b/drivers/mtd/spi/eon.c
@@ -25,8 +25,6 @@
 
 #define EON_ID_EN25Q128		0x18
 
-#define EON_SR_WIP		(1 << 0)	/* Write-in-Progress */
-
 struct eon_spi_flash_params {
 	u8 idcode1;
 	u16 page_size;
@@ -58,40 +56,6 @@
 	},
 };
 
-static int eon_wait_ready(struct spi_flash *flash, unsigned long timeout)
-{
-	struct spi_slave *spi = flash->spi;
-	unsigned long timebase;
-	int ret;
-	u8 cmd = CMD_EN25Q128_RDSR;
-	u8 status;
-
-	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
-	if (ret) {
-		debug("SF: Failed to send command %02x: %d\n", cmd, ret);
-		return ret;
-	}
-
-	timebase = get_timer(0);
-	do {
-		ret = spi_xfer(spi, 8, NULL, &status, 0);
-		if (ret)
-			return -1;
-
-		if ((status & EON_SR_WIP) == 0)
-			break;
-
-	} while (get_timer(timebase) < timeout);
-
-	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
-
-	if ((status & EON_SR_WIP) == 0)
-		return 0;
-
-	/* Timed out */
-	return -1;
-}
-
 static int eon_read_fast(struct spi_flash *flash,
 			 u32 offset, size_t len, void *buf)
 {
@@ -160,11 +124,9 @@
 			break;
 		}
 
-		ret = eon_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: EON page programming timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		if (ret)
 			break;
-		}
 
 		page_addr++;
 		byte_addr = 0;
@@ -221,11 +183,9 @@
 			break;
 		}
 
-		ret = eon_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: EON page erase timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+		if (ret)
 			break;
-		}
 	}
 
 	debug("SF: EON: Successfully erased %u bytes @ 0x%x\n",
diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c
index 76d5284..291fd17 100644
--- a/drivers/mtd/spi/macronix.c
+++ b/drivers/mtd/spi/macronix.c
@@ -49,8 +49,6 @@
 #define CMD_MX25XX_DP		0xb9	/* Deep Power-down */
 #define CMD_MX25XX_RES		0xab	/* Release from DP, and Read Signature */
 
-#define MACRONIX_SR_WIP		(1 << 0)	/* Write-in-Progress */
-
 struct macronix_spi_flash_params {
 	u16 idcode;
 	u16 page_size;
@@ -114,40 +112,6 @@
 	},
 };
 
-static int macronix_wait_ready(struct spi_flash *flash, unsigned long timeout)
-{
-	struct spi_slave *spi = flash->spi;
-	unsigned long timebase;
-	int ret;
-	u8 status;
-	u8 cmd = CMD_MX25XX_RDSR;
-
-	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
-	if (ret) {
-		debug("SF: Failed to send command %02x: %d\n", cmd, ret);
-		return ret;
-	}
-
-	timebase = get_timer(0);
-	do {
-		ret = spi_xfer(spi, 8, NULL, &status, 0);
-		if (ret)
-			return -1;
-
-		if ((status & MACRONIX_SR_WIP) == 0)
-			break;
-
-	} while (get_timer(timebase) < timeout);
-
-	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
-
-	if ((status & MACRONIX_SR_WIP) == 0)
-		return 0;
-
-	/* Timed out */
-	return -1;
-}
-
 static int macronix_read_fast(struct spi_flash *flash,
 			      u32 offset, size_t len, void *buf)
 {
@@ -216,11 +180,9 @@
 			break;
 		}
 
-		ret = macronix_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: Macronix page programming timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		if (ret)
 			break;
-		}
 
 		page_addr++;
 		byte_addr = 0;
@@ -282,11 +244,9 @@
 			break;
 		}
 
-		ret = macronix_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: Macronix page erase timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+		if (ret)
 			break;
-		}
 	}
 
 	debug("SF: Macronix: Successfully erased %u bytes @ 0x%x\n",
diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c
index c0900f9..d0f03ff 100644
--- a/drivers/mtd/spi/spansion.c
+++ b/drivers/mtd/spi/spansion.c
@@ -54,8 +54,6 @@
 #define SPSN_EXT_ID_S25FL128P_64KB	0x0301
 #define SPSN_EXT_ID_S25FL032P		0x4d00
 
-#define SPANSION_SR_WIP		(1 << 0)	/* Write-in-Progress */
-
 struct spansion_spi_flash_params {
 	u16 idcode1;
 	u16 idcode2;
@@ -135,32 +133,6 @@
 	},
 };
 
-static int spansion_wait_ready(struct spi_flash *flash, unsigned long timeout)
-{
-	struct spi_slave *spi = flash->spi;
-	unsigned long timebase;
-	int ret;
-	u8 status;
-
-	timebase = get_timer(0);
-	do {
-		ret = spi_flash_cmd(spi, CMD_S25FLXX_RDSR, &status, sizeof(status));
-		if (ret)
-			return -1;
-
-		if ((status & SPANSION_SR_WIP) == 0)
-			break;
-
-	} while (get_timer(timebase) < timeout);
-
-
-	if ((status & SPANSION_SR_WIP) == 0)
-		return 0;
-
-	/* Timed out */
-	return -1;
-}
-
 static int spansion_read_fast(struct spi_flash *flash,
 			     u32 offset, size_t len, void *buf)
 {
@@ -233,11 +205,9 @@
 			break;
 		}
 
-		ret = spansion_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: SPANSION page programming timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		if (ret)
 			break;
-		}
 
 		page_addr++;
 		byte_addr = 0;
@@ -297,12 +267,9 @@
 			break;
 		}
 
-		/* Up to 2 seconds */
-		ret = spansion_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: SPANSION page erase timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+		if (ret)
 			break;
-		}
 	}
 
 	debug("SF: SPANSION: Successfully erased %u bytes @ 0x%x\n",
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 2b7f22c..e483ce4 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -69,6 +69,47 @@
 	return ret;
 }
 
+int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout,
+			   u8 cmd, u8 poll_bit)
+{
+	struct spi_slave *spi = flash->spi;
+	unsigned long timebase;
+	int ret;
+	u8 status;
+
+	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
+	if (ret) {
+		debug("SF: Failed to send command %02x: %d\n", cmd, ret);
+		return ret;
+	}
+
+	timebase = get_timer(0);
+	do {
+		ret = spi_xfer(spi, 8, NULL, &status, 0);
+		if (ret)
+			return -1;
+
+		if ((status & poll_bit) == 0)
+			break;
+
+	} while (get_timer(timebase) < timeout);
+
+	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
+
+	if ((status & poll_bit) == 0)
+		return 0;
+
+	/* Timed out */
+	debug("SF: time out!\n");
+	return -1;
+}
+
+int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+{
+	return spi_flash_cmd_poll_bit(flash, timeout,
+		CMD_READ_STATUS, STATUS_WIP);
+}
+
 /*
  * The following table holds all device probe functions
  *
diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h
index 68dcffb..440c044 100644
--- a/drivers/mtd/spi/spi_flash_internal.h
+++ b/drivers/mtd/spi/spi_flash_internal.h
@@ -19,6 +19,11 @@
 #define CMD_READ_ARRAY_FAST		0x0b
 #define CMD_READ_ARRAY_LEGACY		0xe8
 
+#define CMD_READ_STATUS			0x05
+
+/* Common status */
+#define STATUS_WIP			0x01
+
 /* Send a single-byte command to the device and read the response */
 int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
 
@@ -43,6 +48,16 @@
 int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
 		size_t cmd_len, void *data, size_t data_len);
 
+/* Send a command to the device and wait for some bit to clear itself. */
+int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout,
+			   u8 cmd, u8 poll_bit);
+
+/*
+ * Send the read status command to the device and wait for the wip
+ * (write-in-progress) bit to clear itself.
+ */
+int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout);
+
 /* Manufacturer-specific probe functions */
 struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode);
 struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode);
diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c
index 2557891..4a82f8a3 100644
--- a/drivers/mtd/spi/sst.c
+++ b/drivers/mtd/spi/sst.c
@@ -90,41 +90,6 @@
 };
 
 static int
-sst_wait_ready(struct spi_flash *flash, unsigned long timeout)
-{
-	struct spi_slave *spi = flash->spi;
-	unsigned long timebase;
-	int ret;
-	u8 byte = CMD_SST_RDSR;
-
-	ret = spi_xfer(spi, sizeof(byte) * 8, &byte, NULL, SPI_XFER_BEGIN);
-	if (ret) {
-		debug("SF: Failed to send command %02x: %d\n", byte, ret);
-		return ret;
-	}
-
-	timebase = get_timer(0);
-	do {
-		ret = spi_xfer(spi, sizeof(byte) * 8, NULL, &byte, 0);
-		if (ret)
-			break;
-
-		if ((byte & SST_SR_WIP) == 0)
-			break;
-
-	} while (get_timer(timebase) < timeout);
-
-	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
-
-	if (!ret && (byte & SST_SR_WIP) != 0)
-		ret = -1;
-
-	if (ret)
-		debug("SF: sst wait for ready timed out\n");
-	return ret;
-}
-
-static int
 sst_enable_writing(struct spi_flash *flash)
 {
 	int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0);
@@ -177,7 +142,7 @@
 	if (ret)
 		return ret;
 
-	return sst_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+	return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
 }
 
 static int
@@ -224,7 +189,7 @@
 			break;
 		}
 
-		ret = sst_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
 		if (ret)
 			break;
 
@@ -298,7 +263,7 @@
 			break;
 		}
 
-		ret = sst_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
 		if (ret)
 			break;
 	}
diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c
index 3134027..02da8b2 100644
--- a/drivers/mtd/spi/stmicro.c
+++ b/drivers/mtd/spi/stmicro.c
@@ -55,8 +55,6 @@
 #define STM_ID_M25P80		0x14
 #define STM_ID_M25P128		0x18
 
-#define STMICRO_SR_WIP		(1 << 0)	/* Write-in-Progress */
-
 struct stmicro_spi_flash_params {
 	u8 idcode1;
 	u16 page_size;
@@ -136,40 +134,6 @@
 	},
 };
 
-static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
-{
-	struct spi_slave *spi = flash->spi;
-	unsigned long timebase;
-	int ret;
-	u8 cmd = CMD_M25PXX_RDSR;
-	u8 status;
-
-	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
-	if (ret) {
-		debug("SF: Failed to send command %02x: %d\n", cmd, ret);
-		return ret;
-	}
-
-	timebase = get_timer(0);
-	do {
-		ret = spi_xfer(spi, 8, NULL, &status, 0);
-		if (ret)
-			return -1;
-
-		if ((status & STMICRO_SR_WIP) == 0)
-			break;
-
-	} while (get_timer(timebase) < timeout);
-
-	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
-
-	if ((status & STMICRO_SR_WIP) == 0)
-		return 0;
-
-	/* Timed out */
-	return -1;
-}
-
 static int stmicro_read_fast(struct spi_flash *flash,
 			     u32 offset, size_t len, void *buf)
 {
@@ -238,11 +202,9 @@
 			break;
 		}
 
-		ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: STMicro page programming timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		if (ret)
 			break;
-		}
 
 		page_addr++;
 		byte_addr = 0;
@@ -304,11 +266,9 @@
 			break;
 		}
 
-		ret = stmicro_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: STMicro page erase timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+		if (ret)
 			break;
-		}
 	}
 
 	debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n",
diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c
index 4452355..d8c1cb1 100644
--- a/drivers/mtd/spi/winbond.c
+++ b/drivers/mtd/spi/winbond.c
@@ -24,8 +24,6 @@
 #define CMD_W25_DP		0xb9	/* Deep Power-down */
 #define CMD_W25_RES		0xab	/* Release from DP, and Read Signature */
 
-#define WINBOND_SR_WIP		(1 << 0)	/* Write-in-Progress */
-
 struct winbond_spi_flash_params {
 	uint16_t	id;
 	/* Log2 of page size in power-of-two mode */
@@ -107,43 +105,6 @@
 	},
 };
 
-static int winbond_wait_ready(struct spi_flash *flash, unsigned long timeout)
-{
-	struct spi_slave *spi = flash->spi;
-	unsigned long timebase;
-	int ret;
-	u8 status;
-	u8 cmd[4] = { CMD_W25_RDSR, 0xff, 0xff, 0xff };
-
-	ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN);
-	if (ret) {
-		debug("SF: Failed to send command %02x: %d\n", cmd, ret);
-		return ret;
-	}
-
-	timebase = get_timer(0);
-	do {
-		ret = spi_xfer(spi, 8, NULL, &status, 0);
-		if (ret) {
-			debug("SF: Failed to get status for cmd %02x: %d\n", cmd, ret);
-			return -1;
-		}
-
-		if ((status & WINBOND_SR_WIP) == 0)
-			break;
-
-	} while (get_timer(timebase) < timeout);
-
-	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
-
-	if ((status & WINBOND_SR_WIP) == 0)
-		return 0;
-
-	debug("SF: Timed out on command %02x: %d\n", cmd, ret);
-	/* Timed out */
-	return -1;
-}
-
 /*
  * Assemble the address part of a command for Winbond devices in
  * non-power-of-two page size mode.
@@ -230,11 +191,9 @@
 			goto out;
 		}
 
-		ret = winbond_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: Winbond page programming timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		if (ret)
 			goto out;
-		}
 
 		page_addr++;
 		byte_addr = 0;
@@ -298,11 +257,9 @@
 			goto out;
 		}
 
-		ret = winbond_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
-		if (ret < 0) {
-			debug("SF: Winbond sector erase timed out\n");
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+		if (ret)
 			goto out;
-		}
 	}
 
 	debug("SF: Winbond: Successfully erased %u bytes @ 0x%x\n",