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);
}
/*
#define EON_ID_EN25Q128 0x18
-#define EON_SR_WIP (1 << 0) /* Write-in-Progress */
-
struct eon_spi_flash_params {
u8 idcode1;
u16 page_size;
},
};
-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)
{
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;
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",
#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;
},
};
-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)
{
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;
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",
#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;
},
};
-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)
{
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;
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",
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
*
#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);
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);
};
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);
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
break;
}
- ret = sst_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+ ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
if (ret)
break;
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;
}
#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;
},
};
-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)
{
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;
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",
#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 */
},
};
-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.
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;
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",