[PATCH v1] mtd: spi-nor: Specify wait ready time for every chip

Haikun Wang haikun.wang at freescale.com
Thu May 14 01:45:52 PDT 2015


Chip erase cycle time is different among different chips.
Cycle time is also differnet among different operations for a special chip.
So we had better use corresponding timeout value for a specail chip and
a special operation when wait chip ready.
This patch add the method to specify the timeout value and use them
when wait chip ready.

Signed-off-by: Haikun Wang <haikun.wang at freescale.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 60 ++++++++++++++++++++++++++++++++-----------
 include/linux/mtd/spi-nor.h   |  4 +++
 2 files changed, 49 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 14a5d23..63a7488 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -46,6 +46,14 @@ struct flash_info {
 	u16		page_size;
 	u16		addr_width;
 
+	/*
+	 * common_wait, wait ready time applying to most operations .
+	 * max_wait defines the max wait ready time.
+	 * Specified in seconds.
+	 */
+	s16		common_wait;
+	s16		max_wait;
+
 	u16		flags;
 #define	SECT_4K			0x01	/* SPINOR_OP_BE_4K works uniformly */
 #define	SPI_NOR_NO_ERASE	0x02	/* No erase command needed */
@@ -231,12 +239,15 @@ static int spi_nor_ready(struct spi_nor *nor)
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
  */
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+static int spi_nor_wait_till_ready(struct spi_nor *nor, int wait_time)
 {
 	unsigned long deadline;
 	int timeout = 0, ret;
 
-	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+	if (wait_time > 0)
+		deadline = jiffies + wait_time * HZ;
+	else
+		deadline = jiffies + MAX_READY_WAIT_JIFFIES;
 
 	while (!timeout) {
 		if (time_after_eq(jiffies, deadline))
@@ -326,7 +337,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 			goto erase_err;
 		}
 
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor, nor->max_wait);
 		if (ret)
 			goto erase_err;
 
@@ -348,7 +359,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 			addr += mtd->erasesize;
 			len -= mtd->erasesize;
 
-			ret = spi_nor_wait_till_ready(nor);
+			ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 			if (ret)
 				goto erase_err;
 		}
@@ -467,8 +478,9 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 	return ret;
 }
 
-/* Used when the "_ext_id" is two bytes at most */
-#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+/* Used when the "_ext_id" is two bytes at most, WATTM: wait time */
+#define INFO_WATTM(_jedec_id, _ext_id, _sector_size, _n_sectors,	\
+		   _common_wait, _max_wait, _flags)			\
 	((kernel_ulong_t)&(struct flash_info) {				\
 		.id = {							\
 			((_jedec_id) >> 16) & 0xff,			\
@@ -481,10 +493,13 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 		.sector_size = (_sector_size),				\
 		.n_sectors = (_n_sectors),				\
 		.page_size = 256,					\
+		.common_wait = (_common_wait),				\
+		.max_wait = (_max_wait),				\
 		.flags = (_flags),					\
 	})
 
-#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+#define INFO6_WATTM(_jedec_id, _ext_id, _sector_size, _n_sectors,	\
+		    _common_wait, _max_wait, _flags)			\
 	((kernel_ulong_t)&(struct flash_info) {				\
 		.id = {							\
 			((_jedec_id) >> 16) & 0xff,			\
@@ -498,6 +513,8 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 		.sector_size = (_sector_size),				\
 		.n_sectors = (_n_sectors),				\
 		.page_size = 256,					\
+		.common_wait = (_common_wait),				\
+		.max_wait = (_max_wait),				\
 		.flags = (_flags),					\
 	})
 
@@ -510,6 +527,16 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 		.flags = (_flags),					\
 	})
 
+#define DEFAULT_WAIT_TIME	40 /* in seconds */
+
+#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+	INFO_WATTM(_jedec_id, _ext_id, _sector_size, _n_sectors,	\
+		    DEFAULT_WAIT_TIME, DEFAULT_WAIT_TIME, _flags)
+
+#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+	INFO6_WATTM(_jedec_id, _ext_id, _sector_size, _n_sectors,	\
+		      DEFAULT_WAIT_TIME, DEFAULT_WAIT_TIME, _flags)
+
 /* NOTE: double check command sets and memory organization when you add
  * more nor chips.  This current list focusses on newer chips, which
  * have been converging on command sets which including JEDEC ID.
@@ -756,7 +783,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 		/* write one byte. */
 		nor->write(nor, to, 1, retlen, buf);
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 		if (ret)
 			goto time_out;
 	}
@@ -768,7 +795,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 		/* write two bytes. */
 		nor->write(nor, to, 2, retlen, buf + actual);
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 		if (ret)
 			goto time_out;
 		to += 2;
@@ -777,7 +804,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 	nor->sst_write_second = false;
 
 	write_disable(nor);
-	ret = spi_nor_wait_till_ready(nor);
+	ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 	if (ret)
 		goto time_out;
 
@@ -788,7 +815,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 		nor->program_opcode = SPINOR_OP_BP;
 		nor->write(nor, to, 1, retlen, buf + actual);
 
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 		if (ret)
 			goto time_out;
 		write_disable(nor);
@@ -834,7 +861,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 			if (page_size > nor->page_size)
 				page_size = nor->page_size;
 
-			ret = spi_nor_wait_till_ready(nor);
+			ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 			if (ret)
 				goto write_err;
 
@@ -844,7 +871,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 		}
 	}
 
-	ret = spi_nor_wait_till_ready(nor);
+	ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 write_err:
 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
 	return ret;
@@ -860,7 +887,7 @@ static int macronix_quad_enable(struct spi_nor *nor)
 	nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
 	nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
 
-	if (spi_nor_wait_till_ready(nor))
+	if (spi_nor_wait_till_ready(nor, nor->common_wait))
 		return 1;
 
 	ret = read_sr(nor);
@@ -931,7 +958,7 @@ static int micron_quad_enable(struct spi_nor *nor)
 		return ret;
 	}
 
-	ret = spi_nor_wait_till_ready(nor);
+	ret = spi_nor_wait_till_ready(nor, nor->common_wait);
 	if (ret)
 		return ret;
 
@@ -1184,6 +1211,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
 	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
 
+	nor->common_wait = info->common_wait;
+	nor->max_wait = info->max_wait;
+
 	dev_info(dev, "%s (%lld Kbytes)\n", id->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index e540952..a0f29c7 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -158,6 +158,8 @@ enum spi_nor_option_flags {
  * @lock:		[FLASH-SPECIFIC] lock a region of the SPI NOR
  * @unlock:		[FLASH-SPECIFIC] unlock a region of the SPI NOR
  * @priv:		the private data
+ * @common_wait:	wait ready time applying to most operations, in seconds
+ * @max_wait:		max wait ready time of all operations, in seconds
  */
 struct spi_nor {
 	struct mtd_info		*mtd;
@@ -195,6 +197,8 @@ struct spi_nor {
 	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
 
 	void *priv;
+	s16			common_wait;
+	s16			max_wait;
 };
 
 /**
-- 
2.1.0.27.g96db324




More information about the linux-mtd mailing list