@@ -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, ®_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, ®_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'