diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index e086d86..9f72df3 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -25,6 +25,7 @@ #include #define SPI_NOR_MAX_ID_LEN 6 +#define SPI_NOR_MAX_ADDR_WIDTH 4 /* * For everything but full-chip erase; probably could be much smaller, but kept @@ -435,6 +436,29 @@ } /* + * Initiate the erasure of a single sector + */ +static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) +{ + u8 buf[SPI_NOR_MAX_ADDR_WIDTH]; + int i; + + if (nor->erase) + return nor->erase(nor, addr); + + /* + * Default implementation, if driver doesn't have a specialized HW + * control + */ + for (i = nor->addr_width - 1; i >= 0; i--) { + buf[i] = addr & 0xff; + addr >>= 8; + } + + return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); +} + +/* * Erase an address range on the nor chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ @@ -498,10 +522,9 @@ while (len) { write_enable(nor); - if (nor->erase(nor, addr)) { - ret = -EIO; + ret = spi_nor_erase_sector(nor, addr); + if (ret) goto erase_err; - } addr += mtd->erasesize; len -= mtd->erasesize; @@ -988,7 +1011,7 @@ static int spi_nor_check(struct spi_nor *nor) { if (!nor->dev || !nor->read || !nor->write || - !nor->read_reg || !nor->write_reg || !nor->erase) { + !nor->read_reg || !nor->write_reg) { pr_err("spi-nor: please fill all the necessary fields!\n"); return -EINVAL; } @@ -1394,6 +1417,12 @@ nor->addr_width = 3; } + if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) { + dev_err(dev, "address width is too large: %u\n", + nor->addr_width); + return -EINVAL; + } + dev_info(dev, "%s (%lld Kbytes)\n", id->name, (long long)mtd->size >> 10); diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index eec5a89..33413ff 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -214,7 +214,8 @@ * @read: [DRIVER-SPECIFIC] read data from the SPI NOR * @write: [DRIVER-SPECIFIC] write data to the SPI NOR * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR - * at the offset @offs + * at the offset @offs; if not provided by the driver, + * spi-nor will send the erase opcode via write_reg() * @priv: the private data */ struct spi_nor {