aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/spi-nor/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/spi-nor/core.c')
-rw-r--r--drivers/mtd/spi-nor/core.c54
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;