mtd: spi-nor: Fix clearing of QE bit on lock()/unlock()
[linux-2.6-microblaze.git] / drivers / mtd / spi-nor / spi-nor.c
index 1d8621d..d696334 100644 (file)
@@ -338,7 +338,7 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
        if (nor->spimem)
                return spi_nor_spimem_read_data(nor, from, len, buf);
 
-       return nor->read(nor, from, len, buf);
+       return nor->controller_ops->read(nor, from, len, buf);
 }
 
 /**
@@ -385,239 +385,172 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
        if (nor->spimem)
                return spi_nor_spimem_write_data(nor, to, len, buf);
 
-       return nor->write(nor, to, len, buf);
+       return nor->controller_ops->write(nor, to, len, buf);
 }
 
-/*
- * Read the status register, returning its value in the location
- * Return the status register value.
- * Returns negative if error occurred.
+/**
+ * spi_nor_write_enable() - Set write enable latch with Write Enable command.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
  */
-static int read_sr(struct spi_nor *nor)
+static int spi_nor_write_enable(struct spi_nor *nor)
 {
        int ret;
 
        if (nor->spimem) {
                struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1),
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREN, 1),
                                   SPI_MEM_OP_NO_ADDR,
                                   SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1));
+                                  SPI_MEM_OP_NO_DATA);
 
                ret = spi_mem_exec_op(nor->spimem, &op);
        } else {
-               ret = nor->read_reg(nor, SPINOR_OP_RDSR, nor->bouncebuf, 1);
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREN,
+                                                    NULL, 0);
        }
 
-       if (ret < 0) {
-               pr_err("error %d reading SR\n", (int) ret);
-               return ret;
-       }
+       if (ret)
+               dev_dbg(nor->dev, "error %d on Write Enable\n", ret);
 
-       return nor->bouncebuf[0];
+       return ret;
 }
 
-/*
- * Read the flag status register, returning its value in the location
- * Return the status register value.
- * Returns negative if error occurred.
+/**
+ * spi_nor_write_disable() - Send Write Disable instruction to the chip.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
  */
-static int read_fsr(struct spi_nor *nor)
+static int spi_nor_write_disable(struct spi_nor *nor)
 {
        int ret;
 
        if (nor->spimem) {
                struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 1),
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRDI, 1),
                                   SPI_MEM_OP_NO_ADDR,
                                   SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1));
+                                  SPI_MEM_OP_NO_DATA);
 
                ret = spi_mem_exec_op(nor->spimem, &op);
        } else {
-               ret = nor->read_reg(nor, SPINOR_OP_RDFSR, nor->bouncebuf, 1);
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRDI,
+                                                    NULL, 0);
        }
 
-       if (ret < 0) {
-               pr_err("error %d reading FSR\n", ret);
-               return ret;
-       }
+       if (ret)
+               dev_dbg(nor->dev, "error %d on Write Disable\n", ret);
 
-       return nor->bouncebuf[0];
+       return ret;
 }
 
-/*
- * Read configuration register, returning its value in the
- * location. Return the configuration register value.
- * Returns negative if error occurred.
+/**
+ * spi_nor_read_sr() - Read the Status Register.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @sr:                pointer to a DMA-able buffer where the value of the
+ *              Status Register will be written.
+ *
+ * Return: 0 on success, -errno otherwise.
  */
-static int read_cr(struct spi_nor *nor)
+static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
 {
        int ret;
 
        if (nor->spimem) {
                struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDCR, 1),
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1),
                                   SPI_MEM_OP_NO_ADDR,
                                   SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1));
+                                  SPI_MEM_OP_DATA_IN(1, sr, 1));
 
                ret = spi_mem_exec_op(nor->spimem, &op);
        } else {
-               ret = nor->read_reg(nor, SPINOR_OP_RDCR, nor->bouncebuf, 1);
+               ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,
+                                                   sr, 1);
        }
 
-       if (ret < 0) {
-               dev_err(nor->dev, "error %d reading CR\n", ret);
-               return ret;
-       }
+       if (ret)
+               dev_dbg(nor->dev, "error %d reading SR\n", ret);
 
-       return nor->bouncebuf[0];
+       return ret;
 }
 
-/*
- * Write status register 1 byte
- * Returns negative if error occurred.
+/**
+ * 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.
+ *
+ * Return: 0 on success, -errno otherwise.
  */
-static int write_sr(struct spi_nor *nor, u8 val)
+static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
 {
-       nor->bouncebuf[0] = val;
-       if (nor->spimem) {
-               struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1),
-                                  SPI_MEM_OP_NO_ADDR,
-                                  SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1));
-
-               return spi_mem_exec_op(nor->spimem, &op);
-       }
-
-       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->bouncebuf, 1);
-}
+       int ret;
 
-/*
- * Set write enable latch with Write Enable command.
- * Returns negative if error occurred.
- */
-static int write_enable(struct spi_nor *nor)
-{
        if (nor->spimem) {
                struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREN, 1),
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 1),
                                   SPI_MEM_OP_NO_ADDR,
                                   SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_NO_DATA);
+                                  SPI_MEM_OP_DATA_IN(1, fsr, 1));
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDFSR,
+                                                   fsr, 1);
        }
 
-       return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
+       if (ret)
+               dev_dbg(nor->dev, "error %d reading FSR\n", ret);
+
+       return ret;
 }
 
-/*
- * Send write disable instruction to the chip.
+/**
+ * spi_nor_read_cr() - Read the Configuration Register using the
+ * SPINOR_OP_RDCR (35h) command.
+ * @nor:       pointer to 'struct spi_nor'
+ * @cr:                pointer to a DMA-able buffer where the value of the
+ *              Configuration Register will be written.
+ *
+ * Return: 0 on success, -errno otherwise.
  */
-static int write_disable(struct spi_nor *nor)
+static int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
 {
+       int ret;
+
        if (nor->spimem) {
                struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRDI, 1),
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDCR, 1),
                                   SPI_MEM_OP_NO_ADDR,
                                   SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_NO_DATA);
+                                  SPI_MEM_OP_DATA_IN(1, cr, 1));
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDCR, cr, 1);
        }
 
-       return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
-}
-
-static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
-{
-       return mtd->priv;
-}
-
-
-static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
-{
-       size_t i;
-
-       for (i = 0; i < size; i++)
-               if (table[i][0] == opcode)
-                       return table[i][1];
-
-       /* No conversion found, keep input op code. */
-       return opcode;
-}
-
-static u8 spi_nor_convert_3to4_read(u8 opcode)
-{
-       static const u8 spi_nor_3to4_read[][2] = {
-               { SPINOR_OP_READ,       SPINOR_OP_READ_4B },
-               { SPINOR_OP_READ_FAST,  SPINOR_OP_READ_FAST_4B },
-               { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B },
-               { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
-               { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
-               { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
-               { SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B },
-               { SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B },
-
-               { SPINOR_OP_READ_1_1_1_DTR,     SPINOR_OP_READ_1_1_1_DTR_4B },
-               { SPINOR_OP_READ_1_2_2_DTR,     SPINOR_OP_READ_1_2_2_DTR_4B },
-               { SPINOR_OP_READ_1_4_4_DTR,     SPINOR_OP_READ_1_4_4_DTR_4B },
-       };
-
-       return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
-                                     ARRAY_SIZE(spi_nor_3to4_read));
-}
-
-static u8 spi_nor_convert_3to4_program(u8 opcode)
-{
-       static const u8 spi_nor_3to4_program[][2] = {
-               { SPINOR_OP_PP,         SPINOR_OP_PP_4B },
-               { SPINOR_OP_PP_1_1_4,   SPINOR_OP_PP_1_1_4_4B },
-               { SPINOR_OP_PP_1_4_4,   SPINOR_OP_PP_1_4_4_4B },
-               { SPINOR_OP_PP_1_1_8,   SPINOR_OP_PP_1_1_8_4B },
-               { SPINOR_OP_PP_1_8_8,   SPINOR_OP_PP_1_8_8_4B },
-       };
-
-       return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
-                                     ARRAY_SIZE(spi_nor_3to4_program));
-}
-
-static u8 spi_nor_convert_3to4_erase(u8 opcode)
-{
-       static const u8 spi_nor_3to4_erase[][2] = {
-               { SPINOR_OP_BE_4K,      SPINOR_OP_BE_4K_4B },
-               { SPINOR_OP_BE_32K,     SPINOR_OP_BE_32K_4B },
-               { SPINOR_OP_SE,         SPINOR_OP_SE_4B },
-       };
-
-       return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase,
-                                     ARRAY_SIZE(spi_nor_3to4_erase));
-}
-
-static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
-{
-       nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
-       nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
-       nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
-
-       if (!spi_nor_has_uniform_erase(nor)) {
-               struct spi_nor_erase_map *map = &nor->params.erase_map;
-               struct spi_nor_erase_type *erase;
-               int i;
+       if (ret)
+               dev_dbg(nor->dev, "error %d reading CR\n", ret);
 
-               for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
-                       erase = &map->erase_type[i];
-                       erase->opcode =
-                               spi_nor_convert_3to4_erase(erase->opcode);
-               }
-       }
+       return ret;
 }
 
+/**
+ * macronix_set_4byte() - Set 4-byte address mode for Macronix flashes.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @enable:    true to enter the 4-byte address mode, false to exit the 4-byte
+ *             address mode.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int macronix_set_4byte(struct spi_nor *nor, bool enable)
 {
+       int ret;
+
        if (nor->spimem) {
                struct spi_mem_op op =
                        SPI_MEM_OP(SPI_MEM_OP_CMD(enable ?
@@ -628,26 +561,55 @@ static int macronix_set_4byte(struct spi_nor *nor, bool enable)
                                  SPI_MEM_OP_NO_DUMMY,
                                  SPI_MEM_OP_NO_DATA);
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor,
+                                                    enable ? SPINOR_OP_EN4B :
+                                                             SPINOR_OP_EX4B,
+                                                    NULL, 0);
        }
 
-       return nor->write_reg(nor, enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B,
-                             NULL, 0);
+       if (ret)
+               dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret);
+
+       return ret;
 }
 
+/**
+ * st_micron_set_4byte() - Set 4-byte address mode for ST and Micron flashes.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @enable:    true to enter the 4-byte address mode, false to exit the 4-byte
+ *             address mode.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int st_micron_set_4byte(struct spi_nor *nor, bool enable)
 {
        int ret;
 
-       write_enable(nor);
+       ret = spi_nor_write_enable(nor);
+       if (ret)
+               return ret;
+
        ret = macronix_set_4byte(nor, enable);
-       write_disable(nor);
+       if (ret)
+               return ret;
 
-       return ret;
+       return spi_nor_write_disable(nor);
 }
 
+/**
+ * spansion_set_4byte() - Set 4-byte address mode for Spansion flashes.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @enable:    true to enter the 4-byte address mode, false to exit the 4-byte
+ *             address mode.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int spansion_set_4byte(struct spi_nor *nor, bool enable)
 {
+       int ret;
+
        nor->bouncebuf[0] = enable << 7;
 
        if (nor->spimem) {
@@ -657,14 +619,29 @@ static int spansion_set_4byte(struct spi_nor *nor, bool enable)
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1));
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_BRWR,
+                                                    nor->bouncebuf, 1);
        }
 
-       return nor->write_reg(nor, SPINOR_OP_BRWR, nor->bouncebuf, 1);
+       if (ret)
+               dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret);
+
+       return ret;
 }
 
+/**
+ * spi_nor_write_ear() - Write Extended Address Register.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @ear:       value to write to the Extended Address Register.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
 {
+       int ret;
+
        nor->bouncebuf[0] = ear;
 
        if (nor->spimem) {
@@ -674,12 +651,26 @@ static int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1));
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREAR,
+                                                    nor->bouncebuf, 1);
        }
 
-       return nor->write_reg(nor, SPINOR_OP_WREAR, nor->bouncebuf, 1);
+       if (ret)
+               dev_dbg(nor->dev, "error %d writing EAR\n", ret);
+
+       return ret;
 }
 
+/**
+ * winbond_set_4byte() - Set 4-byte address mode for Winbond flashes.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @enable:    true to enter the 4-byte address mode, false to exit the 4-byte
+ *             address mode.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int winbond_set_4byte(struct spi_nor *nor, bool enable)
 {
        int ret;
@@ -693,15 +684,29 @@ static int winbond_set_4byte(struct spi_nor *nor, bool enable)
         * Register to be set to 1, so all 3-byte-address reads come from the
         * second 16M. We must clear the register to enable normal behavior.
         */
-       write_enable(nor);
+       ret = spi_nor_write_enable(nor);
+       if (ret)
+               return ret;
+
        ret = spi_nor_write_ear(nor, 0);
-       write_disable(nor);
+       if (ret)
+               return ret;
 
-       return ret;
+       return spi_nor_write_disable(nor);
 }
 
+/**
+ * spi_nor_xread_sr() - Read the Status Register on S3AN flashes.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @sr:                pointer to a DMA-able buffer where the value of the
+ *              Status Register will be written.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr)
 {
+       int ret;
+
        if (nor->spimem) {
                struct spi_mem_op op =
                        SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 1),
@@ -709,27 +714,44 @@ static int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr)
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_IN(1, sr, 1));
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->read_reg(nor, SPINOR_OP_XRDSR,
+                                                   sr, 1);
        }
 
-       return nor->read_reg(nor, SPINOR_OP_XRDSR, sr, 1);
+       if (ret)
+               dev_dbg(nor->dev, "error %d reading XRDSR\n", ret);
+
+       return ret;
 }
 
+/**
+ * s3an_sr_ready() - Query the Status Register of the S3AN flash to see if the
+ * flash is ready for new commands.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int s3an_sr_ready(struct spi_nor *nor)
 {
        int ret;
 
        ret = spi_nor_xread_sr(nor, nor->bouncebuf);
-       if (ret < 0) {
-               dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret);
+       if (ret)
                return ret;
-       }
 
        return !!(nor->bouncebuf[0] & XSR_RDY);
 }
 
-static int spi_nor_clear_sr(struct spi_nor *nor)
+/**
+ * spi_nor_clear_sr() - Clear the Status Register.
+ * @nor:       pointer to 'struct spi_nor'.
+ */
+static void spi_nor_clear_sr(struct spi_nor *nor)
 {
+       int ret;
+
        if (nor->spimem) {
                struct spi_mem_op op =
                        SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 1),
@@ -737,20 +759,33 @@ static int spi_nor_clear_sr(struct spi_nor *nor)
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_NO_DATA);
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLSR,
+                                                    NULL, 0);
        }
 
-       return nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
+       if (ret)
+               dev_dbg(nor->dev, "error %d clearing SR\n", ret);
 }
 
+/**
+ * spi_nor_sr_ready() - Query the Status Register to see if the flash is ready
+ * for new commands.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int spi_nor_sr_ready(struct spi_nor *nor)
 {
-       int sr = read_sr(nor);
-       if (sr < 0)
-               return sr;
+       int ret = spi_nor_read_sr(nor, nor->bouncebuf);
+
+       if (ret)
+               return ret;
 
-       if (nor->flags & SNOR_F_USE_CLSR && sr & (SR_E_ERR | SR_P_ERR)) {
-               if (sr & SR_E_ERR)
+       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");
@@ -759,11 +794,17 @@ static int spi_nor_sr_ready(struct spi_nor *nor)
                return -EIO;
        }
 
-       return !(sr & SR_WIP);
+       return !(nor->bouncebuf[0] & SR_WIP);
 }
 
-static int spi_nor_clear_fsr(struct spi_nor *nor)
+/**
+ * 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, 1),
@@ -771,25 +812,37 @@ static int spi_nor_clear_fsr(struct spi_nor *nor)
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_NO_DATA);
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLFSR,
+                                                    NULL, 0);
        }
 
-       return nor->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.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int spi_nor_fsr_ready(struct spi_nor *nor)
 {
-       int fsr = read_fsr(nor);
-       if (fsr < 0)
-               return fsr;
+       int ret = spi_nor_read_fsr(nor, nor->bouncebuf);
 
-       if (fsr & (FSR_E_ERR | FSR_P_ERR)) {
-               if (fsr & FSR_E_ERR)
+       if (ret)
+               return ret;
+
+       if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) {
+               if (nor->bouncebuf[0] & FSR_E_ERR)
                        dev_err(nor->dev, "Erase operation failed.\n");
                else
                        dev_err(nor->dev, "Program operation failed.\n");
 
-               if (fsr & FSR_PT_ERR)
+               if (nor->bouncebuf[0] & FSR_PT_ERR)
                        dev_err(nor->dev,
                        "Attempted to modify a protected sector.\n");
 
@@ -797,9 +850,15 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
                return -EIO;
        }
 
-       return fsr & FSR_READY;
+       return nor->bouncebuf[0] & FSR_READY;
 }
 
+/**
+ * spi_nor_ready() - Query the flash to see if it is ready for new commands.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int spi_nor_ready(struct spi_nor *nor)
 {
        int sr, fsr;
@@ -816,9 +875,13 @@ static int spi_nor_ready(struct spi_nor *nor)
        return sr && fsr;
 }
 
-/*
- * Service routine to read status register until ready, or timeout occurs.
- * Returns non-zero if error.
+/**
+ * spi_nor_wait_till_ready_with_timeout() - Service routine to read the
+ * Status Register until ready, or timeout occurs.
+ * @nor:               pointer to "struct spi_nor".
+ * @timeout_jiffies:   jiffies to wait until timeout.
+ *
+ * Return: 0 on success, -errno otherwise.
  */
 static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
                                                unsigned long timeout_jiffies)
@@ -838,40 +901,357 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
                if (ret)
                        return 0;
 
-               cond_resched();
-       }
+               cond_resched();
+       }
+
+       dev_dbg(nor->dev, "flash operation timed out\n");
+
+       return -ETIMEDOUT;
+}
+
+/**
+ * spi_nor_wait_till_ready() - Wait for a predefined amount of time for the
+ * flash to be ready, or timeout occurs.
+ * @nor:       pointer to "struct spi_nor".
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_wait_till_ready(struct spi_nor *nor)
+{
+       return spi_nor_wait_till_ready_with_timeout(nor,
+                                                   DEFAULT_READY_WAIT_JIFFIES);
+}
+
+/**
+ * spi_nor_write_sr() - Write the Status Register.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @sr:                pointer to DMA-able buffer to write to the Status Register.
+ * @len:       number of bytes to write to the Status Register.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len)
+{
+       int ret;
+
+       ret = spi_nor_write_enable(nor);
+       if (ret)
+               return ret;
+
+       if (nor->spimem) {
+               struct spi_mem_op op =
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1),
+                                  SPI_MEM_OP_NO_ADDR,
+                                  SPI_MEM_OP_NO_DUMMY,
+                                  SPI_MEM_OP_DATA_OUT(len, sr, 1));
+
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR,
+                                                    sr, len);
+       }
+
+       if (ret) {
+               dev_dbg(nor->dev, "error %d writing SR\n", ret);
+               return ret;
+       }
+
+       return spi_nor_wait_till_ready(nor);
+}
+
+/**
+ * spi_nor_write_sr1_and_check() - Write one byte to the Status Register 1 and
+ * ensure that the byte written match the received value.
+ * @nor:       pointer to a 'struct spi_nor'.
+ * @sr1:       byte value to be written to the Status Register.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_write_sr1_and_check(struct spi_nor *nor, u8 sr1)
+{
+       int ret;
+
+       nor->bouncebuf[0] = sr1;
+
+       ret = spi_nor_write_sr(nor, nor->bouncebuf, 1);
+       if (ret)
+               return ret;
+
+       ret = spi_nor_read_sr(nor, nor->bouncebuf);
+       if (ret)
+               return ret;
+
+       if (nor->bouncebuf[0] != sr1) {
+               dev_dbg(nor->dev, "SR1: read back test failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ * spi_nor_write_16bit_sr_and_check() - Write the Status Register 1 and the
+ * Status Register 2 in one shot. Ensure that the byte written in the Status
+ * Register 1 match the received value, and that the 16-bit Write did not
+ * affect what was already in the Status Register 2.
+ * @nor:       pointer to a 'struct spi_nor'.
+ * @sr1:       byte value to be written to the Status Register 1.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
+{
+       int ret;
+       u8 *sr_cr = nor->bouncebuf;
+       u8 cr_written;
+
+       /* Make sure we don't overwrite the contents of Status Register 2. */
+       if (!(nor->flags & SNOR_F_NO_READ_CR)) {
+               ret = spi_nor_read_cr(nor, &sr_cr[1]);
+               if (ret)
+                       return ret;
+       } else if (nor->params.quad_enable) {
+               /*
+                * If the Status Register 2 Read command (35h) is not
+                * supported, we should at least be sure we don't
+                * change the value of the SR2 Quad Enable bit.
+                *
+                * We can safely assume that when the Quad Enable method is
+                * set, the value of the QE bit is one, as a consequence of the
+                * nor->params.quad_enable() call.
+                *
+                * We can safely assume that the Quad Enable bit is present in
+                * the Status Register 2 at BIT(1). According to the JESD216
+                * revB standard, BFPT DWORDS[15], bits 22:20, the 16-bit
+                * Write Status (01h) command is available just for the cases
+                * in which the QE bit is described in SR2 at BIT(1).
+                */
+               sr_cr[1] = CR_QUAD_EN_SPAN;
+       } else {
+               sr_cr[1] = 0;
+       }
+
+       sr_cr[0] = sr1;
+
+       ret = spi_nor_write_sr(nor, sr_cr, 2);
+       if (ret)
+               return ret;
+
+       if (nor->flags & SNOR_F_NO_READ_CR)
+               return 0;
+
+       cr_written = sr_cr[1];
+
+       ret = spi_nor_read_cr(nor, &sr_cr[1]);
+       if (ret)
+               return ret;
+
+       if (cr_written != sr_cr[1]) {
+               dev_dbg(nor->dev, "CR: read back test failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ * spi_nor_write_sr_and_check() - Write the Status Register 1 and ensure that
+ * the byte written match the received value without affecting other bits in the
+ * Status Register 1 and 2.
+ * @nor:       pointer to a 'struct spi_nor'.
+ * @sr1:       byte value to be written to the Status Register.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1)
+{
+       if (nor->flags & SNOR_F_HAS_16BIT_SR)
+               return spi_nor_write_16bit_sr_and_check(nor, sr1);
+
+       return spi_nor_write_sr1_and_check(nor, sr1);
+}
+
+/**
+ * spi_nor_write_sr2() - Write the Status Register 2 using the
+ * SPINOR_OP_WRSR2 (3eh) command.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @sr2:       pointer to DMA-able buffer to write to the Status Register 2.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_write_sr2(struct spi_nor *nor, const u8 *sr2)
+{
+       int ret;
+
+       ret = spi_nor_write_enable(nor);
+       if (ret)
+               return ret;
+
+       if (nor->spimem) {
+               struct spi_mem_op op =
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR2, 1),
+                                  SPI_MEM_OP_NO_ADDR,
+                                  SPI_MEM_OP_NO_DUMMY,
+                                  SPI_MEM_OP_DATA_OUT(1, sr2, 1));
+
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR2,
+                                                    sr2, 1);
+       }
+
+       if (ret) {
+               dev_dbg(nor->dev, "error %d writing SR2\n", ret);
+               return ret;
+       }
+
+       return spi_nor_wait_till_ready(nor);
+}
+
+/**
+ * spi_nor_read_sr2() - Read the Status Register 2 using the
+ * SPINOR_OP_RDSR2 (3fh) command.
+ * @nor:       pointer to 'struct spi_nor'.
+ * @sr2:       pointer to DMA-able buffer where the value of the
+ *             Status Register 2 will be written.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2)
+{
+       int ret;
+
+       if (nor->spimem) {
+               struct spi_mem_op op =
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR2, 1),
+                                  SPI_MEM_OP_NO_ADDR,
+                                  SPI_MEM_OP_NO_DUMMY,
+                                  SPI_MEM_OP_DATA_IN(1, sr2, 1));
+
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR2,
+                                                   sr2, 1);
+       }
+
+       if (ret)
+               dev_dbg(nor->dev, "error %d reading SR2\n", ret);
+
+       return ret;
+}
+
+/**
+ * spi_nor_erase_chip() - Erase the entire flash memory.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_erase_chip(struct spi_nor *nor)
+{
+       int ret;
+
+       dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
+
+       if (nor->spimem) {
+               struct spi_mem_op op =
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 1),
+                                  SPI_MEM_OP_NO_ADDR,
+                                  SPI_MEM_OP_NO_DUMMY,
+                                  SPI_MEM_OP_NO_DATA);
+
+               ret = spi_mem_exec_op(nor->spimem, &op);
+       } else {
+               ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CHIP_ERASE,
+                                                    NULL, 0);
+       }
+
+       if (ret)
+               dev_dbg(nor->dev, "error %d erasing chip\n", ret);
+
+       return ret;
+}
+
+static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+{
+       return mtd->priv;
+}
+
+static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
+{
+       size_t i;
+
+       for (i = 0; i < size; i++)
+               if (table[i][0] == opcode)
+                       return table[i][1];
+
+       /* No conversion found, keep input op code. */
+       return opcode;
+}
+
+static u8 spi_nor_convert_3to4_read(u8 opcode)
+{
+       static const u8 spi_nor_3to4_read[][2] = {
+               { SPINOR_OP_READ,       SPINOR_OP_READ_4B },
+               { SPINOR_OP_READ_FAST,  SPINOR_OP_READ_FAST_4B },
+               { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B },
+               { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
+               { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
+               { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
+               { SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B },
+               { SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B },
+
+               { SPINOR_OP_READ_1_1_1_DTR,     SPINOR_OP_READ_1_1_1_DTR_4B },
+               { SPINOR_OP_READ_1_2_2_DTR,     SPINOR_OP_READ_1_2_2_DTR_4B },
+               { SPINOR_OP_READ_1_4_4_DTR,     SPINOR_OP_READ_1_4_4_DTR_4B },
+       };
+
+       return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
+                                     ARRAY_SIZE(spi_nor_3to4_read));
+}
 
-       dev_err(nor->dev, "flash operation timed out\n");
+static u8 spi_nor_convert_3to4_program(u8 opcode)
+{
+       static const u8 spi_nor_3to4_program[][2] = {
+               { SPINOR_OP_PP,         SPINOR_OP_PP_4B },
+               { SPINOR_OP_PP_1_1_4,   SPINOR_OP_PP_1_1_4_4B },
+               { SPINOR_OP_PP_1_4_4,   SPINOR_OP_PP_1_4_4_4B },
+               { SPINOR_OP_PP_1_1_8,   SPINOR_OP_PP_1_1_8_4B },
+               { SPINOR_OP_PP_1_8_8,   SPINOR_OP_PP_1_8_8_4B },
+       };
 
-       return -ETIMEDOUT;
+       return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
+                                     ARRAY_SIZE(spi_nor_3to4_program));
 }
 
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+static u8 spi_nor_convert_3to4_erase(u8 opcode)
 {
-       return spi_nor_wait_till_ready_with_timeout(nor,
-                                                   DEFAULT_READY_WAIT_JIFFIES);
+       static const u8 spi_nor_3to4_erase[][2] = {
+               { SPINOR_OP_BE_4K,      SPINOR_OP_BE_4K_4B },
+               { SPINOR_OP_BE_32K,     SPINOR_OP_BE_32K_4B },
+               { SPINOR_OP_SE,         SPINOR_OP_SE_4B },
+       };
+
+       return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase,
+                                     ARRAY_SIZE(spi_nor_3to4_erase));
 }
 
-/*
- * Erase the whole flash memory
- *
- * Returns 0 if successful, non-zero otherwise.
- */
-static int erase_chip(struct spi_nor *nor)
+static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
 {
-       dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
+       nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
+       nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
+       nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
 
-       if (nor->spimem) {
-               struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 1),
-                                  SPI_MEM_OP_NO_ADDR,
-                                  SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_NO_DATA);
+       if (!spi_nor_has_uniform_erase(nor)) {
+               struct spi_nor_erase_map *map = &nor->params.erase_map;
+               struct spi_nor_erase_type *erase;
+               int i;
 
-               return spi_mem_exec_op(nor->spimem, &op);
+               for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+                       erase = &map->erase_type[i];
+                       erase->opcode =
+                               spi_nor_convert_3to4_erase(erase->opcode);
+               }
        }
-
-       return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
 }
 
 static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
@@ -880,10 +1260,9 @@ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
 
        mutex_lock(&nor->lock);
 
-       if (nor->prepare) {
-               ret = nor->prepare(nor, ops);
+       if (nor->controller_ops &&  nor->controller_ops->prepare) {
+               ret = nor->controller_ops->prepare(nor, ops);
                if (ret) {
-                       dev_err(nor->dev, "failed in the preparation.\n");
                        mutex_unlock(&nor->lock);
                        return ret;
                }
@@ -893,8 +1272,8 @@ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
 
 static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
 {
-       if (nor->unprepare)
-               nor->unprepare(nor, ops);
+       if (nor->controller_ops && nor->controller_ops->unprepare)
+               nor->controller_ops->unprepare(nor, ops);
        mutex_unlock(&nor->lock);
 }
 
@@ -935,8 +1314,8 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 
        addr = spi_nor_convert_addr(nor, addr);
 
-       if (nor->erase)
-               return nor->erase(nor, addr);
+       if (nor->controller_ops && nor->controller_ops->erase)
+               return nor->controller_ops->erase(nor, addr);
 
        if (nor->spimem) {
                struct spi_mem_op op =
@@ -957,8 +1336,8 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
                addr >>= 8;
        }
 
-       return nor->write_reg(nor, nor->erase_opcode, nor->bouncebuf,
-                             nor->addr_width);
+       return nor->controller_ops->write_reg(nor, nor->erase_opcode,
+                                             nor->bouncebuf, nor->addr_width);
 }
 
 /**
@@ -1208,7 +1587,9 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
        list_for_each_entry_safe(cmd, next, &erase_list, list) {
                nor->erase_opcode = cmd->opcode;
                while (cmd->count) {
-                       write_enable(nor);
+                       ret = spi_nor_write_enable(nor);
+                       if (ret)
+                               goto destroy_erase_cmd_list;
 
                        ret = spi_nor_erase_sector(nor, addr);
                        if (ret)
@@ -1263,12 +1644,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
        if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
                unsigned long timeout;
 
-               write_enable(nor);
+               ret = spi_nor_write_enable(nor);
+               if (ret)
+                       goto erase_err;
 
-               if (erase_chip(nor)) {
-                       ret = -EIO;
+               ret = spi_nor_erase_chip(nor);
+               if (ret)
                        goto erase_err;
-               }
 
                /*
                 * Scale the timeout linearly with the size of the flash, with
@@ -1291,7 +1673,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
        /* "sector"-at-a-time erase */
        } else if (spi_nor_has_uniform_erase(nor)) {
                while (len) {
-                       write_enable(nor);
+                       ret = spi_nor_write_enable(nor);
+                       if (ret)
+                               goto erase_err;
 
                        ret = spi_nor_erase_sector(nor, addr);
                        if (ret)
@@ -1312,7 +1696,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
                        goto erase_err;
        }
 
-       write_disable(nor);
+       ret = spi_nor_write_disable(nor);
 
 erase_err:
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
@@ -1320,27 +1704,6 @@ erase_err:
        return ret;
 }
 
-/* Write status register and ensure bits in mask match written values */
-static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
-{
-       int ret;
-
-       write_enable(nor);
-       ret = write_sr(nor, status_new);
-       if (ret)
-               return ret;
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret)
-               return ret;
-
-       ret = read_sr(nor);
-       if (ret < 0)
-               return ret;
-
-       return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
-}
-
 static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
                                 uint64_t *len)
 {
@@ -1433,16 +1796,18 @@ static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
 static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
        struct mtd_info *mtd = &nor->mtd;
-       int status_old, status_new;
+       int ret, status_old, status_new;
        u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
        u8 shift = ffs(mask) - 1, pow, val;
        loff_t lock_len;
        bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
        bool use_top;
 
-       status_old = read_sr(nor);
-       if (status_old < 0)
-               return status_old;
+       ret = spi_nor_read_sr(nor, nor->bouncebuf);
+       if (ret)
+               return ret;
+
+       status_old = nor->bouncebuf[0];
 
        /* If nothing in our range is unlocked, we don't need to do anything */
        if (stm_is_locked_sr(nor, ofs, len, status_old))
@@ -1502,7 +1867,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
        if ((status_new & mask) < (status_old & mask))
                return -EINVAL;
 
-       return write_sr_and_check(nor, status_new, mask);
+       return spi_nor_write_sr_and_check(nor, status_new);
 }
 
 /*
@@ -1513,16 +1878,18 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
        struct mtd_info *mtd = &nor->mtd;
-       int status_old, status_new;
+       int ret, status_old, status_new;
        u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
        u8 shift = ffs(mask) - 1, pow, val;
        loff_t lock_len;
        bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
        bool use_top;
 
-       status_old = read_sr(nor);
-       if (status_old < 0)
-               return status_old;
+       ret = spi_nor_read_sr(nor, nor->bouncebuf);
+       if (ret)
+               return ret;
+
+       status_old = nor->bouncebuf[0];
 
        /* If nothing in our range is locked, we don't need to do anything */
        if (stm_is_unlocked_sr(nor, ofs, len, status_old))
@@ -1585,7 +1952,7 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
        if ((status_new & mask) > (status_old & mask))
                return -EINVAL;
 
-       return write_sr_and_check(nor, status_new, mask);
+       return spi_nor_write_sr_and_check(nor, status_new);
 }
 
 /*
@@ -1597,13 +1964,13 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
  */
 static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
-       int status;
+       int ret;
 
-       status = read_sr(nor);
-       if (status < 0)
-               return status;
+       ret = spi_nor_read_sr(nor, nor->bouncebuf);
+       if (ret)
+               return ret;
 
-       return stm_is_locked_sr(nor, ofs, len, status);
+       return stm_is_locked_sr(nor, ofs, len, nor->bouncebuf[0]);
 }
 
 static const struct spi_nor_locking_ops stm_locking_ops = {
@@ -1657,46 +2024,6 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        return ret;
 }
 
-/*
- * Write status Register and configuration register with 2 bytes
- * The first byte will be written to the status register, while the
- * second byte will be written to the configuration register.
- * Return negative if error occurred.
- */
-static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
-{
-       int ret;
-
-       write_enable(nor);
-
-       if (nor->spimem) {
-               struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1),
-                                  SPI_MEM_OP_NO_ADDR,
-                                  SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_OUT(2, sr_cr, 1));
-
-               ret = spi_mem_exec_op(nor->spimem, &op);
-       } else {
-               ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
-       }
-
-       if (ret < 0) {
-               dev_err(nor->dev,
-                       "error while writing configuration register\n");
-               return -EINVAL;
-       }
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret) {
-               dev_err(nor->dev,
-                       "timeout while writing configuration register\n");
-               return ret;
-       }
-
-       return 0;
-}
-
 /**
  * macronix_quad_enable() - set QE bit in Status Register.
  * @nor:       pointer to a 'struct spi_nor'
@@ -1709,70 +2036,28 @@ static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
  */
 static int macronix_quad_enable(struct spi_nor *nor)
 {
-       int ret, val;
-
-       val = read_sr(nor);
-       if (val < 0)
-               return val;
-       if (val & SR_QUAD_EN_MX)
-               return 0;
-
-       write_enable(nor);
-
-       write_sr(nor, val | SR_QUAD_EN_MX);
+       int ret;
 
-       ret = spi_nor_wait_till_ready(nor);
+       ret = spi_nor_read_sr(nor, nor->bouncebuf);
        if (ret)
                return ret;
 
-       ret = read_sr(nor);
-       if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-               dev_err(nor->dev, "Macronix Quad bit not set\n");
-               return -EINVAL;
-       }
+       if (nor->bouncebuf[0] & SR_QUAD_EN_MX)
+               return 0;
 
-       return 0;
-}
+       nor->bouncebuf[0] |= SR_QUAD_EN_MX;
 
-/**
- * spansion_quad_enable() - set QE bit in Configuraiton Register.
- * @nor:       pointer to a 'struct spi_nor'
- *
- * Set the Quad Enable (QE) bit in the Configuration Register.
- * This function is kept for legacy purpose because it has been used for a
- * long time without anybody complaining but it should be considered as
- * deprecated and maybe buggy.
- * First, this function doesn't care about the previous values of the Status
- * and Configuration Registers when it sets the QE bit (bit 1) in the
- * Configuration Register: all other bits are cleared, which may have unwanted
- * side effects like removing some block protections.
- * Secondly, it uses the Read Configuration Register (35h) instruction though
- * some very old and few memories don't support this instruction. If a pull-up
- * resistor is present on the MISO/IO1 line, we might still be able to pass the
- * "read back" test because the QSPI memory doesn't recognize the command,
- * so leaves the MISO/IO1 line state unchanged, hence read_cr() returns 0xFF.
- *
- * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
- * memories.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spansion_quad_enable(struct spi_nor *nor)
-{
-       u8 *sr_cr = nor->bouncebuf;
-       int ret;
+       ret = spi_nor_write_sr(nor, nor->bouncebuf, 1);
+       if (ret)
+               return ret;
 
-       sr_cr[0] = 0;
-       sr_cr[1] = CR_QUAD_EN_SPAN;
-       ret = write_sr_cr(nor, sr_cr);
+       ret = spi_nor_read_sr(nor, nor->bouncebuf);
        if (ret)
                return ret;
 
-       /* read back and check it */
-       ret = read_cr(nor);
-       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-               dev_err(nor->dev, "Spansion Quad bit not set\n");
-               return -EINVAL;
+       if (!(nor->bouncebuf[0] & SR_QUAD_EN_MX)) {
+               dev_dbg(nor->dev, "Macronix Quad bit not set\n");
+               return -EIO;
        }
 
        return 0;
@@ -1797,15 +2082,13 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
        int ret;
 
        /* Keep the current value of the Status Register. */
-       ret = read_sr(nor);
-       if (ret < 0) {
-               dev_err(nor->dev, "error while reading status register\n");
-               return -EINVAL;
-       }
-       sr_cr[0] = ret;
+       ret = spi_nor_read_sr(nor, sr_cr);
+       if (ret)
+               return ret;
+
        sr_cr[1] = CR_QUAD_EN_SPAN;
 
-       return write_sr_cr(nor, sr_cr);
+       return spi_nor_write_sr(nor, sr_cr, 2);
 }
 
 /**
@@ -1823,72 +2106,39 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
  */
 static int spansion_read_cr_quad_enable(struct spi_nor *nor)
 {
-       struct device *dev = nor->dev;
        u8 *sr_cr = nor->bouncebuf;
        int ret;
 
        /* Check current Quad Enable bit value. */
-       ret = read_cr(nor);
-       if (ret < 0) {
-               dev_err(dev, "error while reading configuration register\n");
-               return -EINVAL;
-       }
+       ret = spi_nor_read_cr(nor, &sr_cr[1]);
+       if (ret)
+               return ret;
 
-       if (ret & CR_QUAD_EN_SPAN)
+       if (sr_cr[1] & CR_QUAD_EN_SPAN)
                return 0;
 
-       sr_cr[1] = ret | CR_QUAD_EN_SPAN;
+       sr_cr[1] |= CR_QUAD_EN_SPAN;
 
        /* Keep the current value of the Status Register. */
-       ret = read_sr(nor);
-       if (ret < 0) {
-               dev_err(dev, "error while reading status register\n");
-               return -EINVAL;
-       }
-       sr_cr[0] = ret;
+       ret = spi_nor_read_sr(nor, sr_cr);
+       if (ret)
+               return ret;
 
-       ret = write_sr_cr(nor, sr_cr);
+       ret = spi_nor_write_sr(nor, sr_cr, 2);
        if (ret)
                return ret;
 
        /* Read back and check it. */
-       ret = read_cr(nor);
-       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-               dev_err(nor->dev, "Spansion Quad bit not set\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int spi_nor_write_sr2(struct spi_nor *nor, u8 *sr2)
-{
-       if (nor->spimem) {
-               struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR2, 1),
-                                  SPI_MEM_OP_NO_ADDR,
-                                  SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_OUT(1, sr2, 1));
-
-               return spi_mem_exec_op(nor->spimem, &op);
-       }
-
-       return nor->write_reg(nor, SPINOR_OP_WRSR2, sr2, 1);
-}
-
-static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2)
-{
-       if (nor->spimem) {
-               struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR2, 1),
-                                  SPI_MEM_OP_NO_ADDR,
-                                  SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_IN(1, sr2, 1));
+       ret = spi_nor_read_cr(nor, &sr_cr[1]);
+       if (ret)
+               return ret;
 
-               return spi_mem_exec_op(nor->spimem, &op);
+       if (!(sr_cr[1] & CR_QUAD_EN_SPAN)) {
+               dev_dbg(nor->dev, "Spansion Quad bit not set\n");
+               return -EIO;
        }
 
-       return nor->read_reg(nor, SPINOR_OP_RDSR2, sr2, 1);
+       return 0;
 }
 
 /**
@@ -1918,25 +2168,18 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
        /* Update the Quad Enable bit. */
        *sr2 |= SR2_QUAD_EN_BIT7;
 
-       write_enable(nor);
-
        ret = spi_nor_write_sr2(nor, sr2);
-       if (ret < 0) {
-               dev_err(nor->dev, "error while writing status register 2\n");
-               return -EINVAL;
-       }
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret < 0) {
-               dev_err(nor->dev, "timeout while writing status register 2\n");
+       if (ret)
                return ret;
-       }
 
        /* Read back and check it. */
        ret = spi_nor_read_sr2(nor, sr2);
-       if (!(ret > 0 && (*sr2 & SR2_QUAD_EN_BIT7))) {
-               dev_err(nor->dev, "SR2 Quad bit not set\n");
-               return -EINVAL;
+       if (ret)
+               return ret;
+
+       if (!(*sr2 & SR2_QUAD_EN_BIT7)) {
+               dev_dbg(nor->dev, "SR2 Quad bit not set\n");
+               return -EIO;
        }
 
        return 0;
@@ -1956,24 +2199,13 @@ static int spi_nor_clear_sr_bp(struct spi_nor *nor)
        int ret;
        u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
 
-       ret = read_sr(nor);
-       if (ret < 0) {
-               dev_err(nor->dev, "error while reading status register\n");
+       ret = spi_nor_read_sr(nor, nor->bouncebuf);
+       if (ret)
                return ret;
-       }
-
-       write_enable(nor);
 
-       ret = write_sr(nor, ret & ~mask);
-       if (ret) {
-               dev_err(nor->dev, "write to status register failed\n");
-               return ret;
-       }
+       nor->bouncebuf[0] &= ~mask;
 
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret)
-               dev_err(nor->dev, "timeout while writing status register\n");
-       return ret;
+       return spi_nor_write_sr(nor, nor->bouncebuf, 1);
 }
 
 /**
@@ -1983,9 +2215,9 @@ static int spi_nor_clear_sr_bp(struct spi_nor *nor)
  *
  * Read-modify-write function that clears the Block Protection bits from the
  * Status Register without affecting other bits. The function is tightly
- * coupled with the spansion_quad_enable() function. Both assume that the Write
- * Register with 16 bits, together with the Read Configuration Register (35h)
- * instructions are supported.
+ * coupled with the spansion_read_cr_quad_enable() function. Both assume that
+ * the Write Register with 16 bits, together with the Read Configuration
+ * Register (35h) instructions are supported.
  *
  * Return: 0 on success, -errno otherwise.
  */
@@ -1996,32 +2228,22 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
        u8 *sr_cr =  nor->bouncebuf;
 
        /* Check current Quad Enable bit value. */
-       ret = read_cr(nor);
-       if (ret < 0) {
-               dev_err(nor->dev,
-                       "error while reading configuration register\n");
+       ret = spi_nor_read_cr(nor, &sr_cr[1]);
+       if (ret)
                return ret;
-       }
 
        /*
         * When the configuration register Quad Enable bit is one, only the
         * Write Status (01h) command with two data bytes may be used.
         */
-       if (ret & CR_QUAD_EN_SPAN) {
-               sr_cr[1] = ret;
-
-               ret = read_sr(nor);
-               if (ret < 0) {
-                       dev_err(nor->dev,
-                               "error while reading status register\n");
+       if (sr_cr[1] & CR_QUAD_EN_SPAN) {
+               ret = spi_nor_read_sr(nor, sr_cr);
+               if (ret)
                        return ret;
-               }
-               sr_cr[0] = ret & ~mask;
 
-               ret = write_sr_cr(nor, sr_cr);
-               if (ret)
-                       dev_err(nor->dev, "16-bit write register failed\n");
-               return ret;
+               sr_cr[0] &= ~mask;
+
+               return spi_nor_write_sr(nor, sr_cr, 2);
        }
 
        /*
@@ -2179,6 +2401,8 @@ static const struct flash_info spi_nor_ids[] = {
        { "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
        { "en25q80a",   INFO(0x1c3014, 0, 64 * 1024,   16,
                        SECT_4K | SPI_NOR_DUAL_READ) },
+       { "en25qh16",   INFO(0x1c7015, 0, 64 * 1024,   32,
+                       SECT_4K | SPI_NOR_DUAL_READ) },
        { "en25qh32",   INFO(0x1c7016, 0, 64 * 1024,   64, 0) },
        { "en25qh64",   INFO(0x1c7017, 0, 64 * 1024,  128,
                        SECT_4K | SPI_NOR_DUAL_READ) },
@@ -2520,11 +2744,11 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
 
                tmp = spi_mem_exec_op(nor->spimem, &op);
        } else {
-               tmp = nor->read_reg(nor, SPINOR_OP_RDID, id,
-                                   SPI_NOR_MAX_ID_LEN);
+               tmp = nor->controller_ops->read_reg(nor, SPINOR_OP_RDID, id,
+                                                   SPI_NOR_MAX_ID_LEN);
        }
-       if (tmp < 0) {
-               dev_err(nor->dev, "error %d reading JEDEC ID\n", tmp);
+       if (tmp) {
+               dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
                return ERR_PTR(tmp);
        }
 
@@ -2544,7 +2768,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct spi_nor *nor = mtd_to_spi_nor(mtd);
-       int ret;
+       ssize_t ret;
 
        dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
 
@@ -2583,7 +2807,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, const u_char *buf)
 {
        struct spi_nor *nor = mtd_to_spi_nor(mtd);
-       size_t actual;
+       size_t actual = 0;
        int ret;
 
        dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
@@ -2592,26 +2816,28 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
        if (ret)
                return ret;
 
-       write_enable(nor);
+       ret = spi_nor_write_enable(nor);
+       if (ret)
+               goto out;
 
        nor->sst_write_second = false;
 
-       actual = to % 2;
        /* Start write from odd address. */
-       if (actual) {
+       if (to % 2) {
                nor->program_opcode = SPINOR_OP_BP;
 
                /* write one byte. */
                ret = spi_nor_write_data(nor, to, 1, buf);
                if (ret < 0)
-                       goto sst_write_err;
-               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
-                    (int)ret);
+                       goto out;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
-                       goto sst_write_err;
+                       goto out;
+
+               to++;
+               actual++;
        }
-       to += actual;
 
        /* Write out most of the data here. */
        for (; actual < len - 1; actual += 2) {
@@ -2620,39 +2846,44 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
                /* write two bytes. */
                ret = spi_nor_write_data(nor, to, 2, buf + actual);
                if (ret < 0)
-                       goto sst_write_err;
-               WARN(ret != 2, "While writing 2 bytes written %i bytes\n",
-                    (int)ret);
+                       goto out;
+               WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret);
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
-                       goto sst_write_err;
+                       goto out;
                to += 2;
                nor->sst_write_second = true;
        }
        nor->sst_write_second = false;
 
-       write_disable(nor);
+       ret = spi_nor_write_disable(nor);
+       if (ret)
+               goto out;
+
        ret = spi_nor_wait_till_ready(nor);
        if (ret)
-               goto sst_write_err;
+               goto out;
 
        /* Write out trailing byte if it exists. */
        if (actual != len) {
-               write_enable(nor);
+               ret = spi_nor_write_enable(nor);
+               if (ret)
+                       goto out;
 
                nor->program_opcode = SPINOR_OP_BP;
                ret = spi_nor_write_data(nor, to, 1, buf + actual);
                if (ret < 0)
-                       goto sst_write_err;
-               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
-                    (int)ret);
+                       goto out;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
-                       goto sst_write_err;
-               write_disable(nor);
+                       goto out;
+
                actual += 1;
+
+               ret = spi_nor_write_disable(nor);
        }
-sst_write_err:
+out:
        *retlen += actual;
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
        return ret;
@@ -2701,7 +2932,10 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 
                addr = spi_nor_convert_addr(nor, addr);
 
-               write_enable(nor);
+               ret = spi_nor_write_enable(nor);
+               if (ret)
+                       goto write_err;
+
                ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
                if (ret < 0)
                        goto write_err;
@@ -2722,9 +2956,11 @@ write_err:
 static int spi_nor_check(struct spi_nor *nor)
 {
        if (!nor->dev ||
-           (!nor->spimem &&
-           (!nor->read || !nor->write || !nor->read_reg ||
-             !nor->write_reg))) {
+           (!nor->spimem && nor->controller_ops &&
+           (!nor->controller_ops->read ||
+            !nor->controller_ops->write ||
+            !nor->controller_ops->read_reg ||
+            !nor->controller_ops->write_reg))) {
                pr_err("spi-nor: please fill all the necessary fields!\n");
                return -EINVAL;
        }
@@ -2738,10 +2974,8 @@ static int s3an_nor_setup(struct spi_nor *nor,
        int ret;
 
        ret = spi_nor_xread_sr(nor, nor->bouncebuf);
-       if (ret < 0) {
-               dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret);
+       if (ret)
                return ret;
-       }
 
        nor->erase_opcode = SPINOR_OP_XSE;
        nor->program_opcode = SPINOR_OP_XPP;
@@ -2865,7 +3099,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
  */
 static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf)
 {
-       int ret;
+       ssize_t ret;
 
        while (len) {
                ret = spi_nor_read_data(nor, addr, len, buf);
@@ -3489,19 +3723,38 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
                break;
 
        case BFPT_DWORD15_QER_SR2_BIT1_BUGGY:
+               /*
+                * Writing only one byte to the Status Register has the
+                * side-effect of clearing Status Register 2.
+                */
        case BFPT_DWORD15_QER_SR2_BIT1_NO_RD:
+               /*
+                * Read Configuration Register (35h) instruction is not
+                * supported.
+                */
+               nor->flags |= SNOR_F_HAS_16BIT_SR | SNOR_F_NO_READ_CR;
                params->quad_enable = spansion_no_read_cr_quad_enable;
                break;
 
        case BFPT_DWORD15_QER_SR1_BIT6:
+               nor->flags &= ~SNOR_F_HAS_16BIT_SR;
                params->quad_enable = macronix_quad_enable;
                break;
 
        case BFPT_DWORD15_QER_SR2_BIT7:
+               nor->flags &= ~SNOR_F_HAS_16BIT_SR;
                params->quad_enable = sr2_bit7_quad_enable;
                break;
 
        case BFPT_DWORD15_QER_SR2_BIT1:
+               /*
+                * JESD216 rev B or later does not specify if writing only one
+                * byte to the Status Register clears or not the Status
+                * Register 2, so let's be cautious and keep the default
+                * assumption of a 16-bit Write Status (01h) command.
+                */
+               nor->flags |= SNOR_F_HAS_16BIT_SR;
+
                params->quad_enable = spansion_read_cr_quad_enable;
                break;
 
@@ -4101,7 +4354,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
                err = spi_nor_read_sfdp(nor, sizeof(header),
                                        psize, param_headers);
                if (err < 0) {
-                       dev_err(dev, "failed to read SFDP parameter headers\n");
+                       dev_dbg(dev, "failed to read SFDP parameter headers\n");
                        goto exit;
                }
        }
@@ -4348,7 +4601,7 @@ static int spi_nor_default_setup(struct spi_nor *nor,
        /* Select the (Fast) Read command. */
        err = spi_nor_select_read(nor, shared_mask);
        if (err) {
-               dev_err(nor->dev,
+               dev_dbg(nor->dev,
                        "can't select read settings supported by both the SPI controller and memory.\n");
                return err;
        }
@@ -4356,7 +4609,7 @@ static int spi_nor_default_setup(struct spi_nor *nor,
        /* Select the Page Program command. */
        err = spi_nor_select_pp(nor, shared_mask);
        if (err) {
-               dev_err(nor->dev,
+               dev_dbg(nor->dev,
                        "can't select write settings supported by both the SPI controller and memory.\n");
                return err;
        }
@@ -4364,7 +4617,7 @@ static int spi_nor_default_setup(struct spi_nor *nor,
        /* Select the Sector Erase command. */
        err = spi_nor_select_erase(nor);
        if (err) {
-               dev_err(nor->dev,
+               dev_dbg(nor->dev,
                        "can't select erase settings supported by both the SPI controller and memory.\n");
                return err;
        }
@@ -4465,9 +4718,11 @@ static void spi_nor_info_init_params(struct spi_nor *nor)
        u8 i, erase_mask;
 
        /* Initialize legacy flash parameters and settings. */
-       params->quad_enable = spansion_quad_enable;
+       params->quad_enable = spansion_read_cr_quad_enable;
        params->set_4byte = spansion_set_4byte;
        params->setup = spi_nor_default_setup;
+       /* Default to 16-bit Write Status (01h) Command */
+       nor->flags |= SNOR_F_HAS_16BIT_SR;
 
        /* Set SPI NOR sizes. */
        params->size = (u64)info->sector_size * info->n_sectors;
@@ -4680,12 +4935,12 @@ static int spi_nor_init(struct spi_nor *nor)
        int err;
 
        if (nor->clear_sr_bp) {
-               if (nor->params.quad_enable == spansion_quad_enable)
+               if (nor->params.quad_enable == spansion_read_cr_quad_enable)
                        nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
 
                err = nor->clear_sr_bp(nor);
                if (err) {
-                       dev_err(nor->dev,
+                       dev_dbg(nor->dev,
                                "fail to clear block protection bits\n");
                        return err;
                }
@@ -4693,7 +4948,7 @@ static int spi_nor_init(struct spi_nor *nor)
 
        err = spi_nor_quad_enable(nor);
        if (err) {
-               dev_err(nor->dev, "quad mode not supported\n");
+               dev_dbg(nor->dev, "quad mode not supported\n");
                return err;
        }
 
@@ -4761,7 +5016,7 @@ static int spi_nor_set_addr_width(struct spi_nor *nor)
        }
 
        if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
-               dev_err(nor->dev, "address width is too large: %u\n",
+               dev_dbg(nor->dev, "address width is too large: %u\n",
                        nor->addr_width);
                return -EINVAL;
        }