summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorChunhe Lan <Chunhe.Lan@freescale.com>2014-10-30 11:06:33 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:39:05 (GMT)
commit2e8fef913763401a2fe35ec4eb1658d01a3c0db9 (patch)
tree9d797addbda623a6ef3633571b5a01deb55ce7ce /drivers/mtd
parent330f4843df0ad2e06090ad7b234b34ce48569606 (diff)
downloadlinux-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/mtd')
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c51
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;