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>
This commit is contained in:
Mike Frysinger 2011-01-10 02:20:12 -05:00 committed by Wolfgang Denk
parent 000044d8bf
commit 6163045bcd
9 changed files with 81 additions and 283 deletions

View File

@ -113,35 +113,8 @@ static const struct atmel_spi_flash_params atmel_spi_flash_table[] = {
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);
}
/*

View File

@ -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 const struct eon_spi_flash_params eon_spi_flash_table[] = {
},
};
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 @@ static int eon_write(struct spi_flash *flash,
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 @@ int eon_erase(struct spi_flash *flash, u32 offset, size_t len)
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",

View File

@ -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 const struct macronix_spi_flash_params macronix_spi_flash_table[] = {
},
};
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 @@ static int macronix_write(struct spi_flash *flash,
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 @@ int macronix_erase(struct spi_flash *flash, u32 offset, size_t len)
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",

View File

@ -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 const struct spansion_spi_flash_params spansion_spi_flash_table[] = {
},
};
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 @@ static int spansion_write(struct spi_flash *flash,
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 @@ int spansion_erase(struct spi_flash *flash, u32 offset, size_t len)
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",

View File

@ -69,6 +69,47 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
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
*

View File

@ -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_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_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);

View File

@ -89,41 +89,6 @@ static const struct sst_spi_flash_params sst_spi_flash_table[] = {
},
};
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)
{
@ -177,7 +142,7 @@ sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
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 @@ sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
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 @@ sst_erase(struct spi_flash *flash, u32 offset, size_t len)
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;
}

View File

@ -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 const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
},
};
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 @@ static int stmicro_write(struct spi_flash *flash,
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 @@ int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
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",

View File

@ -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 const struct winbond_spi_flash_params winbond_spi_flash_table[] = {
},
};
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 @@ static int winbond_write(struct spi_flash *flash,
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 @@ int winbond_erase(struct spi_flash *flash, u32 offset, size_t len)
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",