diff options
author | Chunhe Lan <Chunhe.Lan@freescale.com> | 2014-10-30 11:06:33 (GMT) |
---|---|---|
committer | Matthew Weigel <Matthew.Weigel@freescale.com> | 2014-12-11 18:39:05 (GMT) |
commit | 2e8fef913763401a2fe35ec4eb1658d01a3c0db9 (patch) | |
tree | 9d797addbda623a6ef3633571b5a01deb55ce7ce /drivers | |
parent | 330f4843df0ad2e06090ad7b234b34ce48569606 (diff) | |
download | linux-fsl-qoriq-2e8fef913763401a2fe35ec4eb1658d01a3c0db9.tar.xz |
mtd: spi-nor: Add support for flag status register on Micron chips
Some new Micron SPI N25Q512 chips require reading the flag
status register to determine when operations have completed.
Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com>
Change-Id: I52a87e1ae55da75248108d6db39f027318bacf22
Reviewed-on: http://git.am.freescale.net:8181/22632
Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com>
Reviewed-by: Mingkai Hu <Mingkai.Hu@freescale.com>
Reviewed-by: Richard Schmitt <richard.schmitt@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 5df9d0d..dc15574 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -48,6 +48,25 @@ static int read_sr(struct spi_nor *nor) } /* + * 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. * Returns negative if error occured. @@ -178,6 +197,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. @@ -416,6 +461,7 @@ struct flash_info { #define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */ #define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */ #define SPI_NOR_DDR_QUAD_READ 0x80 /* Flash supports DDR Quad Read */ +#define USE_FSR 0x100 /* use flag status register */ }; #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @@ -502,6 +548,7 @@ 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) }, /* PMC */ { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, @@ -1021,6 +1068,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; |