mtd: spi-nor: Rework the disabling of block write protection
[linux-2.6-microblaze.git] / drivers / mtd / spi-nor / spi-nor.c
index 9fd93d8..06aac89 100644 (file)
@@ -388,12 +388,16 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
        return nor->controller_ops->write(nor, to, len, buf);
 }
 
-/*
- * Set write enable latch with Write Enable command.
- * 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 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_WREN, 1),
@@ -401,17 +405,28 @@ static int spi_nor_write_enable(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_WREN,
+                                                    NULL, 0);
        }
 
-       return nor->controller_ops->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
+       if (ret)
+               dev_dbg(nor->dev, "error %d on Write Enable\n", ret);
+
+       return ret;
 }
 
-/*
- * Send write disable instruction to the chip.
+/**
+ * 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 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_WRDI, 1),
@@ -419,10 +434,16 @@ static int spi_nor_write_disable(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_WRDI,
+                                                    NULL, 0);
        }
 
-       return nor->controller_ops->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
+       if (ret)
+               dev_dbg(nor->dev, "error %d on Write Disable\n", ret);
+
+       return ret;
 }
 
 /**
@@ -451,7 +472,7 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
        }
 
        if (ret)
-               pr_err("error %d reading SR\n", ret);
+               dev_dbg(nor->dev, "error %d reading SR\n", ret);
 
        return ret;
 }
@@ -482,7 +503,7 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
        }
 
        if (ret)
-               pr_err("error %d reading FSR\n", ret);
+               dev_dbg(nor->dev, "error %d reading FSR\n", ret);
 
        return ret;
 }
@@ -513,34 +534,23 @@ static int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
        }
 
        if (ret)
-               dev_err(nor->dev, "error %d reading CR\n", ret);
+               dev_dbg(nor->dev, "error %d reading CR\n", ret);
 
        return ret;
 }
 
-/*
- * Write status register 1 byte
- * Returns negative if error occurred.
+/**
+ * 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 spi_nor_write_sr(struct spi_nor *nor, u8 val)
-{
-       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_OUT(1, nor->bouncebuf, 1));
-
-               return spi_mem_exec_op(nor->spimem, &op);
-       }
-
-       return nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR,
-                                             nor->bouncebuf, 1);
-}
-
 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 ?
@@ -551,27 +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->controller_ops->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;
 
-       spi_nor_write_enable(nor);
+       ret = spi_nor_write_enable(nor);
+       if (ret)
+               return ret;
+
        ret = macronix_set_4byte(nor, enable);
-       spi_nor_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) {
@@ -581,15 +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->controller_ops->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) {
@@ -599,13 +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->controller_ops->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;
@@ -619,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.
         */
-       spi_nor_write_enable(nor);
+       ret = spi_nor_write_enable(nor);
+       if (ret)
+               return ret;
+
        ret = spi_nor_write_ear(nor, 0);
-       spi_nor_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),
@@ -635,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->controller_ops->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) {
-               dev_err(nor->dev, "error %d reading XRDSR\n", 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),
@@ -663,12 +759,23 @@ 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->controller_ops->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 ret = spi_nor_read_sr(nor, nor->bouncebuf);
@@ -690,8 +797,14 @@ static int spi_nor_sr_ready(struct spi_nor *nor)
        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),
@@ -699,12 +812,23 @@ 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->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.
+ * @nor:       pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
 static int spi_nor_fsr_ready(struct spi_nor *nor)
 {
        int ret = spi_nor_read_fsr(nor, nor->bouncebuf);
@@ -729,6 +853,12 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
        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;
@@ -745,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)
@@ -770,82 +904,189 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
                cond_resched();
        }
 
-       dev_err(nor->dev, "flash operation timed out\n");
+       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);
 }
 
-/*
- * 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.
+/**
+ * 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_cr(struct spi_nor *nor, u8 *sr_cr)
+static int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len)
 {
        int ret;
 
-       spi_nor_write_enable(nor);
+       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(2, sr_cr, 1));
+                                  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_cr, 2);
+                                                    sr, len);
        }
 
        if (ret) {
-               dev_err(nor->dev,
-                       "error while writing configuration register\n");
-               return -EINVAL;
+               dev_dbg(nor->dev, "error %d writing SR\n", ret);
+               return ret;
        }
 
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret) {
-               dev_err(nor->dev,
-                       "timeout while writing configuration register\n");
+       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;
 }
 
-/* Write status register and ensure bits in mask match written values */
-static int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 status_new,
-                                     u8 mask)
+/**
+ * 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;
 
-       spi_nor_write_enable(nor);
-       ret = spi_nor_write_sr(nor, status_new);
-       if (ret)
-               return ret;
+       /* 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;
+       }
 
-       ret = spi_nor_wait_till_ready(nor);
+       sr_cr[0] = sr1;
+
+       ret = spi_nor_write_sr(nor, sr_cr, 2);
        if (ret)
                return ret;
 
-       ret = spi_nor_read_sr(nor, nor->bouncebuf);
+       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;
 
-       return ((nor->bouncebuf[0] & mask) != (status_new & mask)) ? -EIO : 0;
+       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);
 }
 
-static int spi_nor_write_sr2(struct spi_nor *nor, u8 *sr2)
+/**
+ * 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),
@@ -853,14 +1094,33 @@ static int spi_nor_write_sr2(struct spi_nor *nor, u8 *sr2)
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_OUT(1, sr2, 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_WRSR2,
+                                                    sr2, 1);
        }
 
-       return 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),
@@ -868,19 +1128,28 @@ static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2)
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_IN(1, sr2, 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_RDSR2,
+                                                   sr2, 1);
        }
 
-       return 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;
 }
 
-/*
- * Erase the whole flash memory
+/**
+ * spi_nor_erase_chip() - Erase the entire flash memory.
+ * @nor:       pointer to 'struct spi_nor'.
  *
- * Returns 0 if successful, non-zero otherwise.
+ * 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) {
@@ -890,11 +1159,16 @@ static int spi_nor_erase_chip(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_CHIP_ERASE,
+                                                    NULL, 0);
        }
 
-       return 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)
@@ -1313,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) {
-                       spi_nor_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)
@@ -1368,7 +1644,9 @@ 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;
 
-               spi_nor_write_enable(nor);
+               ret = spi_nor_write_enable(nor);
+               if (ret)
+                       goto erase_err;
 
                ret = spi_nor_erase_chip(nor);
                if (ret)
@@ -1395,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) {
-                       spi_nor_write_enable(nor);
+                       ret = spi_nor_write_enable(nor);
+                       if (ret)
+                               goto erase_err;
 
                        ret = spi_nor_erase_sector(nor, addr);
                        if (ret)
@@ -1416,7 +1696,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
                        goto erase_err;
        }
 
-       spi_nor_write_disable(nor);
+       ret = spi_nor_write_disable(nor);
 
 erase_err:
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
@@ -1587,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 spi_nor_write_sr_and_check(nor, status_new, mask);
+       return spi_nor_write_sr_and_check(nor, status_new);
 }
 
 /*
@@ -1672,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 spi_nor_write_sr_and_check(nor, status_new, mask);
+       return spi_nor_write_sr_and_check(nor, status_new);
 }
 
 /*
@@ -1765,11 +2045,9 @@ static int macronix_quad_enable(struct spi_nor *nor)
        if (nor->bouncebuf[0] & SR_QUAD_EN_MX)
                return 0;
 
-       spi_nor_write_enable(nor);
+       nor->bouncebuf[0] |= SR_QUAD_EN_MX;
 
-       spi_nor_write_sr(nor, nor->bouncebuf[0] | SR_QUAD_EN_MX);
-
-       ret = spi_nor_wait_till_ready(nor);
+       ret = spi_nor_write_sr(nor, nor->bouncebuf, 1);
        if (ret)
                return ret;
 
@@ -1778,56 +2056,8 @@ static int macronix_quad_enable(struct spi_nor *nor)
                return ret;
 
        if (!(nor->bouncebuf[0] & SR_QUAD_EN_MX)) {
-               dev_err(nor->dev, "Macronix Quad bit not set\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**
- * 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 spi_nor_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;
-
-       sr_cr[0] = 0;
-       sr_cr[1] = CR_QUAD_EN_SPAN;
-       ret = spi_nor_write_sr_cr(nor, sr_cr);
-       if (ret)
-               return ret;
-
-       /* read back and check it */
-       ret = spi_nor_read_cr(nor, nor->bouncebuf);
-       if (ret)
-               return ret;
-
-       if (!(nor->bouncebuf[0] & CR_QUAD_EN_SPAN)) {
-               dev_err(nor->dev, "Spansion Quad bit not set\n");
-               return -EINVAL;
+               dev_dbg(nor->dev, "Macronix Quad bit not set\n");
+               return -EIO;
        }
 
        return 0;
@@ -1853,14 +2083,12 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
 
        /* Keep the current value of the Status Register. */
        ret = spi_nor_read_sr(nor, sr_cr);
-       if (ret) {
-               dev_err(nor->dev, "error while reading status register\n");
+       if (ret)
                return ret;
-       }
 
        sr_cr[1] = CR_QUAD_EN_SPAN;
 
-       return spi_nor_write_sr_cr(nor, sr_cr);
+       return spi_nor_write_sr(nor, sr_cr, 2);
 }
 
 /**
@@ -1878,16 +2106,13 @@ 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 = spi_nor_read_cr(nor, &sr_cr[1]);
-       if (ret) {
-               dev_err(dev, "error while reading configuration register\n");
+       if (ret)
                return ret;
-       }
 
        if (sr_cr[1] & CR_QUAD_EN_SPAN)
                return 0;
@@ -1896,12 +2121,10 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
 
        /* Keep the current value of the Status Register. */
        ret = spi_nor_read_sr(nor, sr_cr);
-       if (ret) {
-               dev_err(dev, "error while reading status register\n");
+       if (ret)
                return ret;
-       }
 
-       ret = spi_nor_write_sr_cr(nor, sr_cr);
+       ret = spi_nor_write_sr(nor, sr_cr, 2);
        if (ret)
                return ret;
 
@@ -1911,8 +2134,8 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
                return ret;
 
        if (!(sr_cr[1] & CR_QUAD_EN_SPAN)) {
-               dev_err(nor->dev, "Spansion Quad bit not set\n");
-               return -EINVAL;
+               dev_dbg(nor->dev, "Spansion Quad bit not set\n");
+               return -EIO;
        }
 
        return 0;
@@ -1945,19 +2168,9 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
        /* Update the Quad Enable bit. */
        *sr2 |= SR2_QUAD_EN_BIT7;
 
-       spi_nor_write_enable(nor);
-
        ret = spi_nor_write_sr2(nor, sr2);
-       if (ret) {
-               dev_err(nor->dev, "error while writing status register 2\n");
-               return ret;
-       }
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret) {
-               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);
@@ -1965,101 +2178,13 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
                return ret;
 
        if (!(*sr2 & SR2_QUAD_EN_BIT7)) {
-               dev_err(nor->dev, "SR2 Quad bit not set\n");
-               return -EINVAL;
+               dev_dbg(nor->dev, "SR2 Quad bit not set\n");
+               return -EIO;
        }
 
        return 0;
 }
 
-/**
- * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits.
- * @nor:        pointer to a 'struct spi_nor'
- *
- * Read-modify-write function that clears the Block Protection bits from the
- * Status Register without affecting other bits.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spi_nor_clear_sr_bp(struct spi_nor *nor)
-{
-       int ret;
-       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-
-       ret = spi_nor_read_sr(nor, nor->bouncebuf);
-       if (ret) {
-               dev_err(nor->dev, "error while reading status register\n");
-               return ret;
-       }
-
-       spi_nor_write_enable(nor);
-
-       ret = spi_nor_write_sr(nor, nor->bouncebuf[0] & ~mask);
-       if (ret) {
-               dev_err(nor->dev, "write to status register failed\n");
-               return ret;
-       }
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret)
-               dev_err(nor->dev, "timeout while writing status register\n");
-       return ret;
-}
-
-/**
- * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection
- * bits on spansion flashes.
- * @nor:        pointer to a 'struct spi_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.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
-{
-       int ret;
-       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-       u8 *sr_cr =  nor->bouncebuf;
-
-       /* Check current Quad Enable bit value. */
-       ret = spi_nor_read_cr(nor, &sr_cr[1]);
-       if (ret) {
-               dev_err(nor->dev,
-                       "error while reading configuration register\n");
-               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 (sr_cr[1] & CR_QUAD_EN_SPAN) {
-               ret = spi_nor_read_sr(nor, sr_cr);
-               if (ret) {
-                       dev_err(nor->dev,
-                               "error while reading status register\n");
-                       return ret;
-               }
-
-               sr_cr[0] &= ~mask;
-
-               ret = spi_nor_write_sr_cr(nor, sr_cr);
-               if (ret)
-                       dev_err(nor->dev, "16-bit write register failed\n");
-               return ret;
-       }
-
-       /*
-        * If the Quad Enable bit is zero, use the Write Status (01h) command
-        * with one data byte.
-        */
-       return spi_nor_clear_sr_bp(nor);
-}
-
 /* Used when the "_ext_id" is two bytes at most */
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
                .id = {                                                 \
@@ -2555,7 +2680,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
                                                    SPI_NOR_MAX_ID_LEN);
        }
        if (tmp) {
-               dev_err(nor->dev, "error %d reading JEDEC ID\n", tmp);
+               dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
                return ERR_PTR(tmp);
        }
 
@@ -2575,7 +2700,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);
 
@@ -2614,7 +2739,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);
@@ -2623,25 +2748,28 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
        if (ret)
                return ret;
 
-       spi_nor_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;
+                       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) {
@@ -2650,37 +2778,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;
+                       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;
 
-       spi_nor_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) {
-               spi_nor_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;
+                       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;
-               spi_nor_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;
@@ -2729,7 +2864,10 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 
                addr = spi_nor_convert_addr(nor, addr);
 
-               spi_nor_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;
@@ -2768,10 +2906,8 @@ static int s3an_nor_setup(struct spi_nor *nor,
        int ret;
 
        ret = spi_nor_xread_sr(nor, nor->bouncebuf);
-       if (ret) {
-               dev_err(nor->dev, "error %d reading XRDSR\n", ret);
+       if (ret)
                return ret;
-       }
 
        nor->erase_opcode = SPINOR_OP_XSE;
        nor->program_opcode = SPINOR_OP_XPP;
@@ -2895,7 +3031,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);
@@ -3519,19 +3655,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;
 
@@ -4131,7 +4286,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;
                }
        }
@@ -4378,7 +4533,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;
        }
@@ -4386,7 +4541,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;
        }
@@ -4394,7 +4549,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;
        }
@@ -4411,12 +4566,27 @@ static int spi_nor_setup(struct spi_nor *nor,
        return nor->params.setup(nor, hwcaps);
 }
 
+static void atmel_set_default_init(struct spi_nor *nor)
+{
+       nor->flags |= SNOR_F_HAS_LOCK;
+}
+
+static void intel_set_default_init(struct spi_nor *nor)
+{
+       nor->flags |= SNOR_F_HAS_LOCK;
+}
+
 static void macronix_set_default_init(struct spi_nor *nor)
 {
        nor->params.quad_enable = macronix_quad_enable;
        nor->params.set_4byte = macronix_set_4byte;
 }
 
+static void sst_set_default_init(struct spi_nor *nor)
+{
+       nor->flags |= SNOR_F_HAS_LOCK;
+}
+
 static void st_micron_set_default_init(struct spi_nor *nor)
 {
        nor->flags |= SNOR_F_HAS_LOCK;
@@ -4438,6 +4608,14 @@ static void spi_nor_manufacturer_init_params(struct spi_nor *nor)
 {
        /* Init flash parameters based on MFR */
        switch (JEDEC_MFR(nor->info)) {
+       case SNOR_MFR_ATMEL:
+               atmel_set_default_init(nor);
+               break;
+
+       case SNOR_MFR_INTEL:
+               intel_set_default_init(nor);
+               break;
+
        case SNOR_MFR_MACRONIX:
                macronix_set_default_init(nor);
                break;
@@ -4447,6 +4625,10 @@ static void spi_nor_manufacturer_init_params(struct spi_nor *nor)
                st_micron_set_default_init(nor);
                break;
 
+       case SNOR_MFR_SST:
+               sst_set_default_init(nor);
+               break;
+
        case SNOR_MFR_WINBOND:
                winbond_set_default_init(nor);
                break;
@@ -4495,9 +4677,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;
@@ -4705,25 +4889,36 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
        return nor->params.quad_enable(nor);
 }
 
+/**
+ * spi_nor_unlock_all() - Unlocks the entire flash memory array.
+ * @nor:       pointer to a 'struct spi_nor'.
+ *
+ * Some SPI NOR flashes are write protected by default after a power-on reset
+ * cycle, in order to avoid inadvertent writes during power-up. Backward
+ * compatibility imposes to unlock the entire flash memory array at power-up
+ * by default.
+ */
+static int spi_nor_unlock_all(struct spi_nor *nor)
+{
+       if (nor->flags & SNOR_F_HAS_LOCK)
+               return spi_nor_unlock(&nor->mtd, 0, nor->params.size);
+
+       return 0;
+}
+
 static int spi_nor_init(struct spi_nor *nor)
 {
        int err;
 
-       if (nor->clear_sr_bp) {
-               if (nor->params.quad_enable == spansion_quad_enable)
-                       nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
-
-               err = nor->clear_sr_bp(nor);
-               if (err) {
-                       dev_err(nor->dev,
-                               "fail to clear block protection bits\n");
-                       return err;
-               }
+       err = spi_nor_quad_enable(nor);
+       if (err) {
+               dev_dbg(nor->dev, "quad mode not supported\n");
+               return err;
        }
 
-       err = spi_nor_quad_enable(nor);
+       err = spi_nor_unlock_all(nor);
        if (err) {
-               dev_err(nor->dev, "quad mode not supported\n");
+               dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n");
                return err;
        }
 
@@ -4791,7 +4986,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;
        }
@@ -4909,16 +5104,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
        if (info->flags & SPI_NOR_HAS_LOCK)
                nor->flags |= SNOR_F_HAS_LOCK;
 
-       /*
-        * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
-        * with the software protection bits set.
-        */
-       if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
-           JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
-           JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
-           nor->info->flags & SPI_NOR_HAS_LOCK)
-               nor->clear_sr_bp = spi_nor_clear_sr_bp;
-
        /* Init flash parameters based on flash_info struct and SFDP */
        spi_nor_init_params(nor);