diff options
Diffstat (limited to 'drivers/mtd/spi-nor/core.c')
-rw-r--r-- | drivers/mtd/spi-nor/core.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 2b26a875a855..0410c3d911de 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2185,6 +2185,57 @@ write_err: return ret; } +#if IS_ENABLED(CONFIG_MTD_PSTORE) +static int spi_nor_panic_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + size_t page_offset, page_remain, i; + ssize_t ret; + + if (nor->prepare) { + ret = nor->prepare(nor, SPI_NOR_OPS_WRITE); + if (ret) { + dev_err(nor->dev, "failed in the preparation.\n"); + return ret; + } + } + nor->pstore = 1; + for (i = 0; i < len; ) { + ssize_t written; + loff_t addr = to + i; + + if (hweight32(nor->page_size) == 1) { + page_offset = addr & (nor->page_size - 1); + } else { + uint64_t aux = addr; + + page_offset = do_div(aux, nor->page_size); + } + /* the size of data remaining on the first page */ + page_remain = min_t(size_t, + nor->page_size - page_offset, len - i); + + addr = spi_nor_convert_addr(nor, addr); + + write_enable(nor); + ret = spi_nor_write_data(nor, addr, page_remain, buf + i); + if (ret < 0) + return ret; + written = ret; + while (!spi_nor_ready(nor)) + ; + + *retlen += written; + i += written; + } + + if (nor->unprepare) + nor->unprepare(nor, SPI_NOR_OPS_WRITE); + return 0; +} +#endif + static int spi_nor_check(struct spi_nor *nor) { if (!nor->dev || @@ -3188,6 +3239,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; mtd->_resume = spi_nor_resume; +#if IS_ENABLED(CONFIG_MTD_PSTORE) + mtd->_panic_write = spi_nor_panic_write; +#endif mtd->_get_device = spi_nor_get_device; mtd->_put_device = spi_nor_put_device; |