All of lore.kernel.org
 help / color / mirror / Atom feed
From: tkuw584924@gmail.com
To: linux-mtd@lists.infradead.org
Cc: tudor.ambarus@microchip.com, miquel.raynal@bootlin.com,
	richard@nod.at, vigneshr@ti.com, p.yadav@ti.com,
	Bacem.Daassi@infineon.com,
	Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
Subject: [PATCH v6 1/3] mtd: spi-nor: spansion: Add support for Read/Write Any Register
Date: Wed, 16 Jun 2021 17:44:53 +0900	[thread overview]
Message-ID: <91b246601147a57527e7ceed7303332fae171f52.1623831222.git.Takahiro.Kuwano@infineon.com> (raw)
In-Reply-To: <cover.1623831222.git.Takahiro.Kuwano@infineon.com>

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

Some of Spansion/Cypress chips support Read/Write Any Register commands.
These commands are mainly used to write volatile registers.

The Read Any Register instruction (65h) is followed by register address
and dummy cycles, then the selected register byte is returned.

The Write Any Register instruction (71h) is followed by register address
and register byte to write.

Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
---
Changes in v6:
  - Add helper functions for controller_ops
  - Add 'reg_addr_width' parameter to spansion_read/write_any_reg()
  - Remove spi_nor_write_enable() from spansion_write_any_reg() and modified
    function header comment

Changes in v5:
  - Fix 'if (ret == 1)' to 'if (ret < 0)' in spansion_read_any_reg()

Changes in v4:
  - Fix dummy cycle calculation in spansion_read_any_reg()
  - Modify comment for spansion_write_any_reg()
  
Changes in v3:
  - Cleanup implementation

 drivers/mtd/spi-nor/spansion.c | 142 +++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index b0c5521c1e27..2dd692a7ff24 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -19,6 +19,148 @@
 #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS	0
 #define SPINOR_OP_CYPRESS_RD_FAST		0xee
 
+/**
+ * controller_ops_read_any_reg() - Read Any Register using controller_ops.
+ * @nor:		pointer to a 'struct spi_nor'
+ * @reg_addr:		register address
+ * @reg_addr_width:	number of address bytes
+ * @reg_dummy:		number of dummy cycles for register read
+ * @reg_val:		pointer to a buffer where the register value is copied
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int controller_ops_read_any_reg(struct spi_nor *nor, u32 reg_addr,
+				       u8 reg_addr_width, u8 reg_dummy,
+				       u8 *reg_val)
+{
+	ssize_t ret;
+	enum spi_nor_protocol proto = nor->read_proto;
+	u8 opcode = nor->read_opcode;
+	u8 dummy = nor->read_dummy;
+	u8 addr_width = nor->addr_width;
+
+	nor->read_opcode = SPINOR_OP_RD_ANY_REG;
+	nor->read_dummy = reg_dummy;
+	nor->read_proto = nor->reg_proto;
+	nor->addr_width = reg_addr_width;
+
+	ret = nor->controller_ops->read(nor, reg_addr, 1, reg_val);
+
+	nor->read_opcode = opcode;
+	nor->read_dummy = dummy;
+	nor->read_proto = proto;
+	nor->addr_width = addr_width;
+
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * controller_ops_write_any_reg() - Write Any Register using controller_ops.
+ * @nor:		pointer to a 'struct spi_nor'
+ * @reg_addr:		register address
+ * @reg_addr_width:	number of address bytes
+ * @reg_val:		register value to be written
+ * *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int controller_ops_write_any_reg(struct spi_nor *nor, u32 reg_addr,
+					u8 reg_addr_width, u8 reg_val)
+{
+	ssize_t ret;
+	enum spi_nor_protocol proto = nor->write_proto;
+	u8 opcode = nor->program_opcode;
+	u8 addr_width = nor->addr_width;
+
+	nor->program_opcode = SPINOR_OP_WR_ANY_REG;
+	nor->write_proto = nor->reg_proto;
+	nor->addr_width = reg_addr_width;
+
+	ret = nor->controller_ops->write(nor, reg_addr, 1, &reg_val);
+
+	nor->program_opcode = opcode;
+	nor->write_proto = proto;
+	nor->addr_width = addr_width;
+
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * spansion_read_any_reg() - Read Any Register.
+ * @nor:		pointer to a 'struct spi_nor'
+ * @reg_addr:		register address
+ * @reg_addr_width:	number of address bytes
+ * @reg_dummy:		number of dummy cycles for register read
+ * @reg_val:		pointer to a buffer where the register value is copied
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spansion_read_any_reg(struct spi_nor *nor, u32 reg_addr,
+				 u8 reg_addr_width, u8 reg_dummy, u8 *reg_val)
+{
+	if (nor->spimem) {
+		struct spi_mem_op op =
+			SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0),
+				   SPI_MEM_OP_ADDR(reg_addr_width, reg_addr, 0),
+				   SPI_MEM_OP_DUMMY(reg_dummy, 0),
+				   SPI_MEM_OP_DATA_IN(1, reg_val, 0));
+
+		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+		/* convert the dummy cycles to the number of bytes */
+		op.dummy.nbytes = (reg_dummy * op.dummy.buswidth) / 8;
+		if (spi_nor_protocol_is_dtr(nor->reg_proto))
+			op.dummy.nbytes *= 2;
+
+		return spi_mem_exec_op(nor->spimem, &op);
+	}
+
+	return controller_ops_read_any_reg(nor, reg_addr, reg_addr_width,
+					   reg_dummy, reg_val);
+}
+
+/**
+ * spansion_write_any_reg() - Write Any Register.
+ * @nor:		pointer to a 'struct spi_nor'
+ * @reg_addr:		register address
+ * @reg_addr_width:	number of address bytes
+ * @reg_val:		register value to be written
+ *
+ * spi_nor_write_enable() and spi_nor_write_disable() need to be called before
+ * and after this function. Caller also need to poll status for non-volatile
+ * register. No need to poll status for volatile registers since volatile
+ * register write will be effective immediately after the operation.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spansion_write_any_reg(struct spi_nor *nor, u32 reg_addr,
+				  u8 reg_addr_width, u8 reg_val)
+{
+	if (nor->spimem) {
+		struct spi_mem_op op =
+			SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 0),
+				   SPI_MEM_OP_ADDR(reg_addr_width, reg_addr, 0),
+				   SPI_MEM_OP_NO_DUMMY,
+				   SPI_MEM_OP_DATA_OUT(1, &reg_val, 0));
+
+		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+		return spi_mem_exec_op(nor->spimem, &op);
+	}
+
+	return controller_ops_write_any_reg(nor, reg_addr, reg_addr_width,
+					    reg_val);
+}
+
 /**
  * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
  * @nor:		pointer to a 'struct spi_nor'
-- 
2.25.1


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

  reply	other threads:[~2021-06-16  8:50 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-16  8:44 [PATCH v6 0/3] mtd: spi-nor: Add support for Cypress s25hl-t/s25hs-t tkuw584924
2021-06-16  8:44 ` tkuw584924 [this message]
2021-06-16  8:44 ` [PATCH v6 2/3] mtd: spi-nor: spansion: Add support for volatile QE bit tkuw584924
2021-06-16  8:44 ` [PATCH v6 3/3] mtd: spi-nor: spansion: Add s25hl-t/s25hs-t IDs and fixups tkuw584924
2021-07-15  6:34 ` [PATCH v6 0/3] mtd: spi-nor: Add support for Cypress s25hl-t/s25hs-t Takahiro Kuwano
2021-07-16  6:27   ` Vignesh Raghavendra

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=91b246601147a57527e7ceed7303332fae171f52.1623831222.git.Takahiro.Kuwano@infineon.com \
    --to=tkuw584924@gmail.com \
    --cc=Bacem.Daassi@infineon.com \
    --cc=Takahiro.Kuwano@infineon.com \
    --cc=linux-mtd@lists.infradead.org \
    --cc=miquel.raynal@bootlin.com \
    --cc=p.yadav@ti.com \
    --cc=richard@nod.at \
    --cc=tudor.ambarus@microchip.com \
    --cc=vigneshr@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.