diff options
Diffstat (limited to 'drivers/mtd/spi/spi_flash.c')
-rw-r--r-- | drivers/mtd/spi/spi_flash.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index e483ce4..ca4bbb2 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -14,6 +14,14 @@ #include "spi_flash_internal.h" +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + static int spi_flash_read_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, const u8 *data_out, u8 *data_in, @@ -110,6 +118,56 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) CMD_READ_STATUS, STATUS_WIP); } +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 erase_size, u32 offset, size_t len) +{ + u32 start, end; + int ret; + u8 cmd[4]; + + if (offset % erase_size || len % erase_size) { + debug("SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + debug("SF: Successfully erased %lu bytes @ %#x\n", + len * erase_size, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + /* * The following table holds all device probe functions * |