mtd: spi-nor: add support for flag status register on Micron chips
authorgrmoore@altera.com <grmoore@altera.com>
Tue, 29 Apr 2014 15:29:51 +0000 (10:29 -0500)
committerBrian Norris <computersforpeace@gmail.com>
Sat, 12 Jul 2014 02:10:35 +0000 (19:10 -0700)
Some new Micron flash chips require reading the flag status register to
determine when operations have completed.

Furthermore, chips with multi-die stacks of the 65nm 256Mb QSPI also
require reading the status register before reading the flag status
register.

This patch adds support for the flag status register in the n25q512ax3
and n25q00 Micron QSPI flash chips.

Signed-off-by: Graham Moore <grmoore@altera.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
drivers/mtd/spi-nor/spi-nor.c
include/linux/mtd/spi-nor.h

index c713c865671026a220332263e3086eb7c10674a4..7da3a7067c3570398245188c41002b4546d519a2 100644 (file)
@@ -47,6 +47,25 @@ static int read_sr(struct spi_nor *nor)
        return val;
 }
 
+/*
+ * Read the flag status register, returning its value in the location
+ * Return the status register value.
+ * Returns negative if error occurred.
+ */
+static int read_fsr(struct spi_nor *nor)
+{
+       int ret;
+       u8 val;
+
+       ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
+       if (ret < 0) {
+               pr_err("error %d reading FSR\n", ret);
+               return ret;
+       }
+
+       return val;
+}
+
 /*
  * Read configuration register, returning its value in the
  * location. Return the configuration register value.
@@ -165,6 +184,32 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
        return -ETIMEDOUT;
 }
 
+static int spi_nor_wait_till_fsr_ready(struct spi_nor *nor)
+{
+       unsigned long deadline;
+       int sr;
+       int fsr;
+
+       deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+
+       do {
+               cond_resched();
+
+               sr = read_sr(nor);
+               if (sr < 0) {
+                       break;
+               } else if (!(sr & SR_WIP)) {
+                       fsr = read_fsr(nor);
+                       if (fsr < 0)
+                               break;
+                       if (fsr & FSR_READY)
+                               return 0;
+               }
+       } while (!time_after_eq(jiffies, deadline));
+
+       return -ETIMEDOUT;
+}
+
 /*
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
@@ -402,6 +447,7 @@ struct flash_info {
 #define        SECT_4K_PMC             0x10    /* SPINOR_OP_BE_4K_PMC works uniformly */
 #define        SPI_NOR_DUAL_READ       0x20    /* Flash supports Dual Read */
 #define        SPI_NOR_QUAD_READ       0x40    /* Flash supports Quad Read */
+#define        USE_FSR                 0x80    /* use flag status register */
 };
 
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
@@ -488,6 +534,8 @@ const struct spi_device_id spi_nor_ids[] = {
        { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, 0) },
        { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K) },
        { "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) },
+       { "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) },
+       { "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) },
 
        /* PMC */
        { "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
@@ -965,6 +1013,10 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
        else
                mtd->_write = spi_nor_write;
 
+       if ((info->flags & USE_FSR) &&
+           nor->wait_till_ready == spi_nor_wait_till_ready)
+               nor->wait_till_ready = spi_nor_wait_till_fsr_ready;
+
        /* prefer "small sector" erase if possible */
        if (info->flags & SECT_4K) {
                nor->erase_opcode = SPINOR_OP_BE_4K;
index 53241842a7ab4dc7e823b157fe10f98050eee86a..9e6294f32ba88fffb4c126c6ee7478c04f657eba 100644 (file)
@@ -34,6 +34,7 @@
 #define SPINOR_OP_SE           0xd8    /* Sector erase (usually 64KiB) */
 #define SPINOR_OP_RDID         0x9f    /* Read JEDEC ID */
 #define SPINOR_OP_RDCR         0x35    /* Read configuration register */
+#define SPINOR_OP_RDFSR                0x70    /* Read flag status register */
 
 /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
 #define SPINOR_OP_READ4                0x13    /* Read data bytes (low frequency) */
@@ -66,6 +67,9 @@
 
 #define SR_QUAD_EN_MX          0x40    /* Macronix Quad I/O */
 
+/* Flag Status Register bits */
+#define FSR_READY              0x80
+
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN                0x2     /* Spansion Quad I/O */
 
This page took 0.028718 seconds and 5 git commands to generate.