aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/spi-nor/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/spi-nor/core.c')
-rw-r--r--drivers/mtd/spi-nor/core.c49
1 files changed, 44 insertions, 5 deletions
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 20df44b753da..0522304f52fa 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -465,7 +465,7 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
*
* Return: 0 on success, -errno otherwise.
*/
-static int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
+int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
{
int ret;
@@ -854,6 +854,43 @@ int spi_nor_wait_till_ready(struct spi_nor *nor)
}
/**
+ * spi_nor_global_block_unlock() - Unlock Global Block Protection.
+ * @nor: pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+int spi_nor_global_block_unlock(struct spi_nor *nor)
+{
+ 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_GBULK, 0),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_DATA);
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ } else {
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_GBULK,
+ NULL, 0);
+ }
+
+ if (ret) {
+ dev_dbg(nor->dev, "error %d on Global Block Unlock\n", ret);
+ return ret;
+ }
+
+ return spi_nor_wait_till_ready(nor);
+}
+
+/**
* 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.
@@ -1364,14 +1401,15 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
erase = &map->erase_type[i];
+ /* Alignment is not mandatory for overlaid regions */
+ if (region->offset & SNOR_OVERLAID_REGION &&
+ region->size <= len)
+ return erase;
+
/* Don't erase more than what the user has asked for. */
if (erase->size > len)
continue;
- /* Alignment is not mandatory for overlaid regions */
- if (region->offset & SNOR_OVERLAID_REGION)
- return erase;
-
spi_nor_div_by_erase_size(erase, addr, &rem);
if (rem)
continue;
@@ -1515,6 +1553,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
goto destroy_erase_cmd_list;
if (prev_erase != erase ||
+ erase->size != cmd->size ||
region->offset & SNOR_OVERLAID_REGION) {
cmd = spi_nor_init_erase_cmd(region, erase);
if (IS_ERR(cmd)) {