linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/3] mtd: spi-nor: core: Add the ->ready() hook
@ 2021-04-16  7:31 yaliang.wang
  2021-04-16  7:31 ` [PATCH v2 2/3] mtd: spi-nor: core: reuse spi_nor_clear_sr and spi_nor_read_sr functions yaliang.wang
  2021-04-16  7:31 ` [PATCH v2 3/3] mtd: spi-nor: core: move Spansion checking ready codes into spansion.c yaliang.wang
  0 siblings, 2 replies; 3+ messages in thread
From: yaliang.wang @ 2021-04-16  7:31 UTC (permalink / raw)
  To: tudor.ambarus, miquel.raynal, richard, vigneshr, nicolas.ferre,
	alexandre.belloni, ludovic.desroches
  Cc: linux-mtd, Takahiro Kuwano, Pratyush Yadav, Yaliang Wang

From: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>

This hook can be used for SPI NOR flashes that do not support default
status read method.

Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
Reviewed-by: Pratyush Yadav <p.yadav@ti.com>
Signed-off-by: Yaliang Wang <Yaliang.Wang@windriver.com>
---
Changes in v2:
  - Totally reuse the patch Takahiro made [1], this patch is introduced
	as the base of the following patches.
    [1]http://lists.infradead.org/pipermail/linux-mtd/2021-March/085741.html

 drivers/mtd/spi-nor/core.c | 8 +++++---
 drivers/mtd/spi-nor/core.h | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 0522304f52fa..5de72322ae32 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -785,12 +785,13 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
 }
 
 /**
- * spi_nor_ready() - Query the flash to see if it is ready for new commands.
+ * spi_nor_default_ready() - Query the flash to see if it is ready for new
+ * commands.
  * @nor:	pointer to 'struct spi_nor'.
  *
  * Return: 1 if ready, 0 if not ready, -errno on errors.
  */
-static int spi_nor_ready(struct spi_nor *nor)
+static int spi_nor_default_ready(struct spi_nor *nor)
 {
 	int sr, fsr;
 
@@ -826,7 +827,7 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
 		if (time_after_eq(jiffies, deadline))
 			timeout = 1;
 
-		ret = spi_nor_ready(nor);
+		ret = nor->params->ready(nor);
 		if (ret < 0)
 			return ret;
 		if (ret)
@@ -2920,6 +2921,7 @@ static void spi_nor_info_init_params(struct spi_nor *nor)
 	params->quad_enable = spi_nor_sr2_bit1_quad_enable;
 	params->set_4byte_addr_mode = spansion_set_4byte_addr_mode;
 	params->setup = spi_nor_default_setup;
+	params->ready = spi_nor_default_ready;
 	/* Default to 16-bit Write Status (01h) Command */
 	nor->flags |= SNOR_F_HAS_16BIT_SR;
 
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 4a3f7f150b5d..cf265044b543 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -218,6 +218,7 @@ struct spi_nor_locking_ops {
  *                      flashes that have peculiarities to the SPI NOR standard
  *                      e.g. different opcodes, specific address calculation,
  *                      page size, etc.
+ * @ready:             checks if the SPI NOR flash is ready.
  * @locking_ops:	SPI NOR locking methods.
  */
 struct spi_nor_flash_parameter {
@@ -238,6 +239,7 @@ struct spi_nor_flash_parameter {
 	int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
 	u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
 	int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
+	int (*ready)(struct spi_nor *nor);
 
 	const struct spi_nor_locking_ops *locking_ops;
 };
-- 
2.25.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/3] mtd: spi-nor: core: reuse spi_nor_clear_sr and spi_nor_read_sr functions
  2021-04-16  7:31 [PATCH v2 1/3] mtd: spi-nor: core: Add the ->ready() hook yaliang.wang
@ 2021-04-16  7:31 ` yaliang.wang
  2021-04-16  7:31 ` [PATCH v2 3/3] mtd: spi-nor: core: move Spansion checking ready codes into spansion.c yaliang.wang
  1 sibling, 0 replies; 3+ messages in thread
From: yaliang.wang @ 2021-04-16  7:31 UTC (permalink / raw)
  To: tudor.ambarus, miquel.raynal, richard, vigneshr, nicolas.ferre,
	alexandre.belloni, ludovic.desroches
  Cc: linux-mtd, Yaliang Wang

From: Yaliang Wang <Yaliang.Wang@windriver.com>

spi_nor_clear_fsr() and spi_nor_read_fsr() two functions are almost the
same with the functions spi_nor_clear_sr() and spi_nor_read_sr(), with
little change, the last two functions' codes can be reused, and can be
easily expanded to other manufacturers or chips.

Also, rename spi_nor_clear_sr() as spi_nor_clear_status()
spi_nor_read_sr() as spi_nor_read_status(), because they no longer just
deal with a specific register now, they deal with one type of registers.

Signed-off-by: Yaliang Wang <Yaliang.Wang@windriver.com>
---
New in v2:
  - Also reuse spi_nor_read_sr() codes.
Changes in v2:
  - Rename spi_nor_read_sr() to spi_nor_read_status()
  - Rename spi_nor_clear_sr() to spi_nor_clear_status()

 drivers/mtd/spi-nor/atmel.c |   4 +-
 drivers/mtd/spi-nor/core.c  | 119 ++++++++----------------------------
 drivers/mtd/spi-nor/core.h  |   2 +-
 3 files changed, 28 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/spi-nor/atmel.c b/drivers/mtd/spi-nor/atmel.c
index 1fea5cab492c..769299d06f78 100644
--- a/drivers/mtd/spi-nor/atmel.c
+++ b/drivers/mtd/spi-nor/atmel.c
@@ -76,7 +76,7 @@ static int atmel_set_global_protection(struct spi_nor *nor, loff_t ofs,
 	if (ofs || len != nor->params->size)
 		return -EINVAL;
 
-	ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 	if (ret)
 		return ret;
 
@@ -133,7 +133,7 @@ static int atmel_is_global_protected(struct spi_nor *nor, loff_t ofs, uint64_t l
 	if (ofs >= nor->params->size || (ofs + len) > nor->params->size)
 		return -EINVAL;
 
-	ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 5de72322ae32..0e7fcbc4136f 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -370,23 +370,24 @@ int spi_nor_write_disable(struct spi_nor *nor)
 }
 
 /**
- * spi_nor_read_sr() - Read the Status Register.
+ * spi_nor_read_status() - Read the chip status.
  * @nor:	pointer to 'struct spi_nor'.
- * @sr:		pointer to a DMA-able buffer where the value of the
+ * @opcode:	the SPI command op code to get the chip status
+ * @st:		pointer to a DMA-able buffer where the value of the
  *              Status Register will be written. Should be at least 2 bytes.
  *
  * Return: 0 on success, -errno otherwise.
  */
-int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
+int spi_nor_read_status(struct spi_nor *nor, u8 opcode, u8 *st)
 {
 	int ret;
 
 	if (nor->spimem) {
 		struct spi_mem_op op =
-			SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 0),
+			SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0),
 				   SPI_MEM_OP_NO_ADDR,
 				   SPI_MEM_OP_NO_DUMMY,
-				   SPI_MEM_OP_DATA_IN(1, sr, 0));
+				   SPI_MEM_OP_DATA_IN(1, st, 0));
 
 		if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
 			op.addr.nbytes = nor->params->rdsr_addr_nbytes;
@@ -402,56 +403,12 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
 
 		ret = spi_mem_exec_op(nor->spimem, &op);
 	} else {
-		ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDSR, sr,
+		ret = spi_nor_controller_ops_read_reg(nor, opcode, st,
 						      1);
 	}
 
 	if (ret)
-		dev_dbg(nor->dev, "error %d reading SR\n", ret);
-
-	return ret;
-}
-
-/**
- * spi_nor_read_fsr() - Read the Flag Status Register.
- * @nor:	pointer to 'struct spi_nor'
- * @fsr:	pointer to a DMA-able buffer where the value of the
- *              Flag Status Register will be written. Should be at least 2
- *              bytes.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
-{
-	int ret;
-
-	if (nor->spimem) {
-		struct spi_mem_op op =
-			SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),
-				   SPI_MEM_OP_NO_ADDR,
-				   SPI_MEM_OP_NO_DUMMY,
-				   SPI_MEM_OP_DATA_IN(1, fsr, 0));
-
-		if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
-			op.addr.nbytes = nor->params->rdsr_addr_nbytes;
-			op.dummy.nbytes = nor->params->rdsr_dummy;
-			/*
-			 * We don't want to read only one byte in DTR mode. So,
-			 * read 2 and then discard the second byte.
-			 */
-			op.data.nbytes = 2;
-		}
-
-		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
-
-		ret = spi_mem_exec_op(nor->spimem, &op);
-	} else {
-		ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
-						      1);
-	}
-
-	if (ret)
-		dev_dbg(nor->dev, "error %d reading FSR\n", ret);
+		dev_dbg(nor->dev, "error %d reading status\n", ret);
 
 	return ret;
 }
@@ -650,16 +607,17 @@ static int spi_nor_xsr_ready(struct spi_nor *nor)
 }
 
 /**
- * spi_nor_clear_sr() - Clear the Status Register.
+ * spi_nor_clear_status() - Clear the chip's abnormal status.
  * @nor:	pointer to 'struct spi_nor'.
+ * @opcode:	the SPI command op code to clear the obnormal status.
  */
-static void spi_nor_clear_sr(struct spi_nor *nor)
+static void spi_nor_clear_status(struct spi_nor *nor, u8 opcode)
 {
 	int ret;
 
 	if (nor->spimem) {
 		struct spi_mem_op op =
-			SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0),
+			SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0),
 				   SPI_MEM_OP_NO_ADDR,
 				   SPI_MEM_OP_NO_DUMMY,
 				   SPI_MEM_OP_NO_DATA);
@@ -668,12 +626,12 @@ static void spi_nor_clear_sr(struct spi_nor *nor)
 
 		ret = spi_mem_exec_op(nor->spimem, &op);
 	} else {
-		ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
+		ret = spi_nor_controller_ops_write_reg(nor, opcode,
 						       NULL, 0);
 	}
 
 	if (ret)
-		dev_dbg(nor->dev, "error %d clearing SR\n", ret);
+		dev_dbg(nor->dev, "error %d clearing status\n", ret);
 }
 
 /**
@@ -685,7 +643,7 @@ static void spi_nor_clear_sr(struct spi_nor *nor)
  */
 static int spi_nor_sr_ready(struct spi_nor *nor)
 {
-	int ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	int ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 
 	if (ret)
 		return ret;
@@ -697,7 +655,7 @@ static int spi_nor_sr_ready(struct spi_nor *nor)
 		else
 			dev_err(nor->dev, "Programming Error occurred\n");
 
-		spi_nor_clear_sr(nor);
+		spi_nor_clear_status(nor, SPINOR_OP_CLSR);
 
 		/*
 		 * WEL bit remains set to one when an erase or page program
@@ -715,33 +673,6 @@ static int spi_nor_sr_ready(struct spi_nor *nor)
 	return !(nor->bouncebuf[0] & SR_WIP);
 }
 
-/**
- * spi_nor_clear_fsr() - Clear the Flag Status Register.
- * @nor:	pointer to 'struct spi_nor'.
- */
-static void spi_nor_clear_fsr(struct spi_nor *nor)
-{
-	int ret;
-
-	if (nor->spimem) {
-		struct spi_mem_op op =
-			SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0),
-				   SPI_MEM_OP_NO_ADDR,
-				   SPI_MEM_OP_NO_DUMMY,
-				   SPI_MEM_OP_NO_DATA);
-
-		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
-
-		ret = spi_mem_exec_op(nor->spimem, &op);
-	} else {
-		ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
-						       NULL, 0);
-	}
-
-	if (ret)
-		dev_dbg(nor->dev, "error %d clearing FSR\n", ret);
-}
-
 /**
  * spi_nor_fsr_ready() - Query the Flag Status Register to see if the flash is
  * ready for new commands.
@@ -751,7 +682,7 @@ static void spi_nor_clear_fsr(struct spi_nor *nor)
  */
 static int spi_nor_fsr_ready(struct spi_nor *nor)
 {
-	int ret = spi_nor_read_fsr(nor, nor->bouncebuf);
+	int ret = spi_nor_read_status(nor, SPINOR_OP_RDFSR, nor->bouncebuf);
 
 	if (ret)
 		return ret;
@@ -766,7 +697,7 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
 			dev_err(nor->dev,
 			"Attempted to modify a protected sector.\n");
 
-		spi_nor_clear_fsr(nor);
+		spi_nor_clear_status(nor, SPINOR_OP_CLFSR);
 
 		/*
 		 * WEL bit remains set to one when an erase or page program
@@ -948,7 +879,7 @@ static int spi_nor_write_sr1_and_check(struct spi_nor *nor, u8 sr1)
 	if (ret)
 		return ret;
 
-	ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 	if (ret)
 		return ret;
 
@@ -1042,7 +973,7 @@ static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr)
 	u8 sr_written;
 
 	/* Keep the current value of the Status Register 1. */
-	ret = spi_nor_read_sr(nor, sr_cr);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, sr_cr);
 	if (ret)
 		return ret;
 
@@ -1054,7 +985,7 @@ static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr)
 
 	sr_written = sr_cr[0];
 
-	ret = spi_nor_read_sr(nor, sr_cr);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, sr_cr);
 	if (ret)
 		return ret;
 
@@ -1878,7 +1809,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
 	bool use_top;
 
-	ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 	if (ret)
 		return ret;
 
@@ -1963,7 +1894,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
 	bool use_top;
 
-	ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 	if (ret)
 		return ret;
 
@@ -2040,7 +1971,7 @@ static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
 	int ret;
 
-	ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 	if (ret)
 		return ret;
 
@@ -2111,7 +2042,7 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor)
 {
 	int ret;
 
-	ret = spi_nor_read_sr(nor, nor->bouncebuf);
+	ret = spi_nor_read_status(nor, SPINOR_OP_RDSR, nor->bouncebuf);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index cf265044b543..02c12e04811d 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -442,7 +442,7 @@ void spi_nor_unlock_and_unprep(struct spi_nor *nor);
 int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
 int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
 int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
-int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
+int spi_nor_read_status(struct spi_nor *nor, u8 opcode, u8 *st);
 int spi_nor_read_cr(struct spi_nor *nor, u8 *cr);
 int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
 int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
-- 
2.25.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 3/3] mtd: spi-nor: core: move Spansion checking ready codes into spansion.c
  2021-04-16  7:31 [PATCH v2 1/3] mtd: spi-nor: core: Add the ->ready() hook yaliang.wang
  2021-04-16  7:31 ` [PATCH v2 2/3] mtd: spi-nor: core: reuse spi_nor_clear_sr and spi_nor_read_sr functions yaliang.wang
@ 2021-04-16  7:31 ` yaliang.wang
  1 sibling, 0 replies; 3+ messages in thread
From: yaliang.wang @ 2021-04-16  7:31 UTC (permalink / raw)
  To: tudor.ambarus, miquel.raynal, richard, vigneshr, nicolas.ferre,
	alexandre.belloni, ludovic.desroches
  Cc: linux-mtd, Yaliang Wang

From: Yaliang Wang <Yaliang.Wang@windriver.com>

For historical reasons, Many manufacturer codes exist in the core, to
make the core a more dedicated place, this commit clear the
Spansion-specific checking SR ready codes out of the core.

Signed-off-by: Yaliang Wang <Yaliang.Wang@windriver.com>
---
Changes in v2:
  - Rename spansion_sr_ready() to spansion_status_ready()

 drivers/mtd/spi-nor/core.c     | 26 +-----------------
 drivers/mtd/spi-nor/core.h     |  2 +-
 drivers/mtd/spi-nor/spansion.c | 48 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h    |  1 -
 4 files changed, 50 insertions(+), 27 deletions(-)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 0e7fcbc4136f..2a0dc8778bc6 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -611,7 +611,7 @@ static int spi_nor_xsr_ready(struct spi_nor *nor)
  * @nor:	pointer to 'struct spi_nor'.
  * @opcode:	the SPI command op code to clear the obnormal status.
  */
-static void spi_nor_clear_status(struct spi_nor *nor, u8 opcode)
+void spi_nor_clear_status(struct spi_nor *nor, u8 opcode)
 {
 	int ret;
 
@@ -648,28 +648,6 @@ static int spi_nor_sr_ready(struct spi_nor *nor)
 	if (ret)
 		return ret;
 
-	if (nor->flags & SNOR_F_USE_CLSR &&
-	    nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
-		if (nor->bouncebuf[0] & SR_E_ERR)
-			dev_err(nor->dev, "Erase Error occurred\n");
-		else
-			dev_err(nor->dev, "Programming Error occurred\n");
-
-		spi_nor_clear_status(nor, SPINOR_OP_CLSR);
-
-		/*
-		 * WEL bit remains set to one when an erase or page program
-		 * error occurs. Issue a Write Disable command to protect
-		 * against inadvertent writes that can possibly corrupt the
-		 * contents of the memory.
-		 */
-		ret = spi_nor_write_disable(nor);
-		if (ret)
-			return ret;
-
-		return -EIO;
-	}
-
 	return !(nor->bouncebuf[0] & SR_WIP);
 }
 
@@ -3445,8 +3423,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 
 	if (info->flags & NO_CHIP_ERASE)
 		nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
-	if (info->flags & USE_CLSR)
-		nor->flags |= SNOR_F_USE_CLSR;
 	if (info->flags & SPI_NOR_SWP_IS_VOLATILE)
 		nor->flags |= SNOR_F_SWP_IS_VOLATILE;
 
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 02c12e04811d..3c047c9ef372 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -16,7 +16,6 @@ enum spi_nor_option_flags {
 	SNOR_F_HAS_SR_TB	= BIT(1),
 	SNOR_F_NO_OP_CHIP_ERASE	= BIT(2),
 	SNOR_F_READY_XSR_RDY	= BIT(3),
-	SNOR_F_USE_CLSR		= BIT(4),
 	SNOR_F_BROKEN_RESET	= BIT(5),
 	SNOR_F_4B_OPCODES	= BIT(6),
 	SNOR_F_HAS_4BAIT	= BIT(7),
@@ -446,6 +445,7 @@ int spi_nor_read_status(struct spi_nor *nor, u8 opcode, u8 *st);
 int spi_nor_read_cr(struct spi_nor *nor, u8 *cr);
 int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
 int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
+void spi_nor_clear_status(struct spi_nor *nor, u8 opcode);
 
 int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
 ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index b0c5521c1e27..824aaa4ff536 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -18,6 +18,48 @@
 #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN	0x3
 #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS	0
 #define SPINOR_OP_CYPRESS_RD_FAST		0xee
+#define SPINOR_OP_SPANSION_CLSR			0x30
+
+/**
+ * spansion_status_ready() - Spansion specific method for querying the flash to
+ * see if it is ready for new commands.
+ * @nor:   pointer to 'struct spi_nor'.
+ *
+ * Return: 1 if ready, 0 if not ready, -errno on errors.
+ */
+static int spansion_status_ready(struct spi_nor *nor)
+{
+	u8 *st = nor->bouncebuf;
+	int ret;
+
+	ret = spi_nor_read_status(nor, st);
+	if (ret)
+		return ret;
+
+	if (nor->info->flags & USE_CLSR &&
+	    nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
+		if (nor->bouncebuf[0] & SR_E_ERR)
+			dev_err(nor->dev, "Erase Error occurred\n");
+		else
+			dev_err(nor->dev, "Programming Error occurred\n");
+
+		spi_nor_clear_status(nor, SPINOR_OP_SPANSION_CLSR);
+
+		/*
+		 * WEL bit remains set to one when an erase or page program
+		 * error occurs. Issue a Write Disable command to protect
+		 * against inadvertent writes that can possibly corrupt the
+		 * contents of the memory.
+		 */
+		ret = spi_nor_write_disable(nor);
+		if (ret)
+			return ret;
+
+		return -EIO;
+	}
+
+	return !(st[0] & SR_WIP);
+}
 
 /**
  * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
@@ -289,8 +331,14 @@ static void spansion_post_sfdp_fixups(struct spi_nor *nor)
 	nor->mtd.erasesize = nor->info->sector_size;
 }
 
+static void spansion_default_init(struct spi_nor *nor)
+{
+	nor->params->ready = spansion_status_ready;
+}
+
 static const struct spi_nor_fixups spansion_fixups = {
 	.post_sfdp = spansion_post_sfdp_fixups,
+	.default_init = spansion_default_init,
 };
 
 const struct spi_nor_manufacturer spi_nor_spansion = {
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index a0d572855444..87e03943ba94 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -101,7 +101,6 @@
 
 /* Used for Spansion flashes only. */
 #define SPINOR_OP_BRWR		0x17	/* Bank register write */
-#define SPINOR_OP_CLSR		0x30	/* Clear status register 1 */
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_RD_EVCR      0x65    /* Read EVCR register */
-- 
2.25.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-04-16  7:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-16  7:31 [PATCH v2 1/3] mtd: spi-nor: core: Add the ->ready() hook yaliang.wang
2021-04-16  7:31 ` [PATCH v2 2/3] mtd: spi-nor: core: reuse spi_nor_clear_sr and spi_nor_read_sr functions yaliang.wang
2021-04-16  7:31 ` [PATCH v2 3/3] mtd: spi-nor: core: move Spansion checking ready codes into spansion.c yaliang.wang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).