[PATCH v3 08/17] mtd: spinand: Add support for manufacturer-based ctrl_ops variations

From: Apurva Nandan
Date: Sat Jan 01 2022 - 02:44:06 EST


Add ctrl_ops_variants, which can be used by the manufacturers' codes
to define their SPI control operation variants. Add a macro to easily
define ctrl_ops_varinats. This can be used to list out all the
supported ctrl ops with their respective protocols by the vendors.

Add spinand_select_ctrl_ops_variant() helper function to search for
a supported ctrl_ops variant with the required SPI protocol in a given
list of variants.

Signed-off-by: Apurva Nandan <a-nandan@xxxxxx>
---
drivers/mtd/nand/spi/core.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/mtd/spinand.h | 17 +++++++++++++++++
2 files changed, 53 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 30e90527ee3c..9688fdfc174e 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1031,6 +1031,42 @@ spinand_select_data_op_variant(struct spinand_device *spinand,
return NULL;
}

+static const struct spinand_ctrl_ops *
+spinand_select_ctrl_ops_variant(struct spinand_device *spinand,
+ const struct spinand_ctrl_ops_variants *variants,
+ const enum spinand_protocol protocol)
+{
+ unsigned int i;
+
+ for (i = 0; i < variants->nvariants; i++) {
+ const struct spinand_ctrl_ops *ctrl_ops =
+ &variants->ctrl_ops_list[i];
+
+ if (ctrl_ops->protocol != protocol)
+ continue;
+
+ if (!spi_mem_supports_op(spinand->spimem,
+ &ctrl_ops->ops.reset) ||
+ !spi_mem_supports_op(spinand->spimem,
+ &ctrl_ops->ops.get_feature) ||
+ !spi_mem_supports_op(spinand->spimem,
+ &ctrl_ops->ops.set_feature) ||
+ !spi_mem_supports_op(spinand->spimem,
+ &ctrl_ops->ops.write_enable) ||
+ !spi_mem_supports_op(spinand->spimem,
+ &ctrl_ops->ops.block_erase) ||
+ !spi_mem_supports_op(spinand->spimem,
+ &ctrl_ops->ops.page_read) ||
+ !spi_mem_supports_op(spinand->spimem,
+ &ctrl_ops->ops.program_execute))
+ continue;
+
+ return ctrl_ops;
+ }
+
+ return NULL;
+}
+
/**
* spinand_match_and_init() - Try to find a match between a device ID and an
* entry in a spinand_info table
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index e5df6220ec1e..5dae0649f2fb 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -385,6 +385,18 @@ struct spinand_ctrl_ops {
.protocol = __protocol, \
}

+struct spinand_ctrl_ops_variants {
+ const struct spinand_ctrl_ops *ctrl_ops_list;
+ unsigned int nvariants;
+};
+
+#define SPINAND_CTRL_OPS_VARIANTS(name, ...) \
+ const struct spinand_ctrl_ops_variants name = { \
+ .ctrl_ops_list = (struct spinand_ctrl_ops[]){ __VA_ARGS__ }, \
+ .nvariants = sizeof((struct spinand_ctrl_ops[]){ __VA_ARGS__ })/\
+ sizeof(struct spinand_ctrl_ops), \
+ }
+
/**
* spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
* chip
@@ -442,6 +454,8 @@ struct spinand_info {
const struct spinand_op_variants *write_cache;
const struct spinand_op_variants *update_cache;
} data_ops_variants;
+
+ const struct spinand_ctrl_ops_variants *ctrl_ops_variants;
int (*select_target)(struct spinand_device *spinand,
unsigned int target);
};
@@ -460,6 +474,9 @@ struct spinand_info {
.update_cache = __update, \
}

+#define SPINAND_INFO_CTRL_OPS_VARIANTS(__ctrl_ops_variants) \
+ .ctrl_ops_variants = __ctrl_ops_variants
+
#define SPINAND_ECCINFO(__ooblayout, __get_status) \
.eccinfo = { \
.ooblayout = __ooblayout, \
--
2.25.1