[PATCH v2 04/11] spi: spi-mem: Transform the read operation template

From: Miquel Raynal

Date: Thu Mar 26 2026 - 12:49:24 EST


As of now, we only use a single operation template when creating SPI
memory direct mappings. With the idea to extend this possibility to 2,
rename the template to reflect that we are currently setting the
"primary" operation, and create a pointer in the same structure to point
to it.

>From a user point of view, the op_tmpl name remains but becomes a
pointer, leading to minor changes in both the SPI NAND and SPI NOR
cores.

There is no functional change.

Acked-by: Mark Brown <broonie@xxxxxxxxxx>
Signed-off-by: Miquel Raynal <miquel.raynal@xxxxxxxxxxx>
---
drivers/mtd/nand/spi/core.c | 15 ++++++++-------
drivers/mtd/spi-nor/core.c | 22 ++++++++++++----------
drivers/spi/spi-mem.c | 15 ++++++++-------
include/linux/spi/spi-mem.h | 3 ++-
4 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 663f5d6a6bd7..a66510747b31 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -491,9 +491,9 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,

if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED &&
req->mode != MTD_OPS_RAW)
- rdesc->info.op_tmpl.data.ecc = true;
+ rdesc->info.op_tmpl->data.ecc = true;
else
- rdesc->info.op_tmpl.data.ecc = false;
+ rdesc->info.op_tmpl->data.ecc = false;

if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT)
column |= req->pos.plane << fls(nanddev_page_size(nand));
@@ -586,9 +586,9 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,

if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED &&
req->mode != MTD_OPS_RAW)
- wdesc->info.op_tmpl.data.ecc = true;
+ wdesc->info.op_tmpl->data.ecc = true;
else
- wdesc->info.op_tmpl.data.ecc = false;
+ wdesc->info.op_tmpl->data.ecc = false;

if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT)
column |= req->pos.plane << fls(nanddev_page_size(nand));
@@ -1247,7 +1247,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand,

/* Write descriptor */
info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
- info.op_tmpl.data.ecc = enable_ecc;
+ info.primary_op_tmpl = *spinand->op_templates->update_cache;
+ info.primary_op_tmpl.data.ecc = enable_ecc;
desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
spinand->spimem, &info);
if (IS_ERR(desc))
@@ -1256,8 +1257,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
spinand->dirmaps[plane].wdesc = desc;

/* Read descriptor */
- info.op_tmpl = *spinand->op_templates->read_cache;
- info.op_tmpl.data.ecc = enable_ecc;
+ info.primary_op_tmpl = *spinand->op_templates->read_cache;
+ info.primary_op_tmpl.data.ecc = enable_ecc;
desc = spinand_create_rdesc(spinand, &info);
if (IS_ERR(desc))
return PTR_ERR(desc);
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 8ffeb41c3e08..84b98d6b12cd 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -3641,14 +3641,15 @@ EXPORT_SYMBOL_GPL(spi_nor_scan);
static int spi_nor_create_read_dirmap(struct spi_nor *nor)
{
struct spi_mem_dirmap_info info = {
- .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
- SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0),
- SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
- SPI_MEM_OP_DATA_IN(0, NULL, 0)),
+ .op_tmpl = &info.primary_op_tmpl,
+ .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
+ SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0),
+ SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
+ SPI_MEM_OP_DATA_IN(0, NULL, 0)),
.offset = 0,
.length = nor->params->size,
};
- struct spi_mem_op *op = &info.op_tmpl;
+ struct spi_mem_op *op = info.op_tmpl;

spi_nor_spimem_setup_op(nor, op, nor->read_proto);

@@ -3672,14 +3673,15 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor)
static int spi_nor_create_write_dirmap(struct spi_nor *nor)
{
struct spi_mem_dirmap_info info = {
- .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0),
- SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0),
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(0, NULL, 0)),
+ .op_tmpl = &info.primary_op_tmpl,
+ .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0),
+ SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(0, NULL, 0)),
.offset = 0,
.length = nor->params->size,
};
- struct spi_mem_op *op = &info.op_tmpl;
+ struct spi_mem_op *op = info.op_tmpl;

if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
op->addr.nbytes = 0;
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index a09371a075d2..e2eaa1ba4ff6 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -647,7 +647,7 @@ EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);
static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
- struct spi_mem_op op = desc->info.op_tmpl;
+ struct spi_mem_op op = *desc->info.op_tmpl;
int ret;

op.addr.val = desc->info.offset + offs;
@@ -667,7 +667,7 @@ static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, const void *buf)
{
- struct spi_mem_op op = desc->info.op_tmpl;
+ struct spi_mem_op op = *desc->info.op_tmpl;
int ret;

op.addr.val = desc->info.offset + offs;
@@ -706,11 +706,11 @@ spi_mem_dirmap_create(struct spi_mem *mem,
int ret = -ENOTSUPP;

/* Make sure the number of address cycles is between 1 and 8 bytes. */
- if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8)
+ if (!info->primary_op_tmpl.addr.nbytes || info->primary_op_tmpl.addr.nbytes > 8)
return ERR_PTR(-EINVAL);

/* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */
- if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA)
+ if (info->primary_op_tmpl.data.dir == SPI_MEM_NO_DATA)
return ERR_PTR(-EINVAL);

desc = kzalloc_obj(*desc);
@@ -719,6 +719,7 @@ spi_mem_dirmap_create(struct spi_mem *mem,

desc->mem = mem;
desc->info = *info;
+ desc->info.op_tmpl = &desc->info.primary_op_tmpl;
if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) {
ret = spi_mem_access_start(mem);
if (ret) {
@@ -733,7 +734,7 @@ spi_mem_dirmap_create(struct spi_mem *mem,

if (ret) {
desc->nodirmap = true;
- if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
+ if (!spi_mem_supports_op(desc->mem, &desc->info.primary_op_tmpl))
ret = -EOPNOTSUPP;
else
ret = 0;
@@ -857,7 +858,7 @@ ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
struct spi_controller *ctlr = desc->mem->spi->controller;
ssize_t ret;

- if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+ if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN)
return -EINVAL;

if (!len)
@@ -903,7 +904,7 @@ ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
struct spi_controller *ctlr = desc->mem->spi->controller;
ssize_t ret;

- if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_OUT)
+ if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_OUT)
return -EINVAL;

if (!len)
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 5774e554c0f0..3cba7fe4bed5 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -225,7 +225,8 @@ struct spi_mem_op {
* direction is directly encoded in the ->op_tmpl.data.dir field.
*/
struct spi_mem_dirmap_info {
- struct spi_mem_op op_tmpl;
+ struct spi_mem_op *op_tmpl;
+ struct spi_mem_op primary_op_tmpl;
u64 offset;
u64 length;
};

--
2.51.1