Align code and behavior with linux-7.3.

Changes:
 * add comments
 * use the same error codes as used in linux
 * add more checks for spi_mem_op
 * add macros necessary for spinand dtr support
 * remove unused macros

Signed-off-by: Mikhail Kshevetskiy <[email protected]>
---
 drivers/spi/spi-mem.c | 65 +++++++++++++++++++++++++++++++++++--------
 include/spi-mem.h     | 26 +++++++++++++++--
 2 files changed, 77 insertions(+), 14 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index ae393ca48bc..8ceebc2be7d 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -22,8 +22,11 @@
 #include <dm/device_compat.h>
 #include <dm/devres.h>
 #include <linux/bug.h>
+#include <linux/bitops.h>
 #endif
 
+#define SPI_MEM_MAX_BUSWIDTH           8
+
 #ifndef __UBOOT__
 /**
  * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
@@ -213,6 +216,45 @@ bool spi_mem_default_supports_op(struct spi_slave *slave,
 }
 EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
 
+static bool spi_mem_buswidth_is_valid(u8 buswidth)
+{
+       if (hweight8(buswidth) > 1 || buswidth > SPI_MEM_MAX_BUSWIDTH)
+               return false;
+
+       return true;
+}
+
+static int spi_mem_check_op(const struct spi_mem_op *op)
+{
+       if (!op->cmd.buswidth || !op->cmd.nbytes)
+               return -EINVAL;
+
+       if ((op->addr.nbytes && !op->addr.buswidth) ||
+           (op->dummy.nbytes && !op->dummy.buswidth) ||
+           (op->data.nbytes && !op->data.buswidth))
+               return -EINVAL;
+
+       if (!spi_mem_buswidth_is_valid(op->cmd.buswidth) ||
+           !spi_mem_buswidth_is_valid(op->addr.buswidth) ||
+           !spi_mem_buswidth_is_valid(op->dummy.buswidth) ||
+           !spi_mem_buswidth_is_valid(op->data.buswidth))
+               return -EINVAL;
+
+       return 0;
+}
+
+static bool spi_mem_internal_supports_op(struct spi_slave *slave,
+                                        const struct spi_mem_op *op)
+{
+       struct udevice *bus = slave->dev->parent;
+       struct dm_spi_ops *ops = spi_get_ops(bus);
+
+       if (ops->mem_ops && ops->mem_ops->supports_op)
+               return ops->mem_ops->supports_op(slave, op);
+
+       return spi_mem_default_supports_op(slave, op);
+}
+
 /**
  * spi_mem_supports_op() - Check if a memory device and the controller it is
  *                        connected to support a specific memory operation
@@ -231,13 +273,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
 bool spi_mem_supports_op(struct spi_slave *slave,
                         const struct spi_mem_op *op)
 {
-       struct udevice *bus = slave->dev->parent;
-       struct dm_spi_ops *ops = spi_get_ops(bus);
-
-       if (ops->mem_ops && ops->mem_ops->supports_op)
-               return ops->mem_ops->supports_op(slave, op);
+       if (spi_mem_check_op(op))
+               return false;
 
-       return spi_mem_default_supports_op(slave, op);
+       return spi_mem_internal_supports_op(slave, op);
 }
 EXPORT_SYMBOL_GPL(spi_mem_supports_op);
 
@@ -265,8 +304,12 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct 
spi_mem_op *op)
        int ret;
        int i;
 
-       if (!spi_mem_supports_op(slave, op))
-               return -ENOTSUPP;
+       ret = spi_mem_check_op(op);
+       if (ret)
+               return ret;
+
+       if (!spi_mem_internal_supports_op(slave, op))
+               return -EOPNOTSUPP;
 
        ret = spi_claim_bus(slave);
        if (ret < 0)
@@ -629,7 +672,7 @@ spi_mem_dirmap_create(struct spi_slave *slave,
        struct udevice *bus = slave->dev->parent;
        struct dm_spi_ops *ops = spi_get_ops(bus);
        struct spi_mem_dirmap_desc *desc;
-       int ret = -EOPNOTSUPP;
+       int ret = -ENOTSUPP;
 
        /* Make sure the number of address cycles is between 1 and 8 bytes. */
        if (!info->primary_op_tmpl.addr.nbytes || 
info->primary_op_tmpl.addr.nbytes > 8)
@@ -807,7 +850,7 @@ ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc 
*desc,
        else if (ops->mem_ops && ops->mem_ops->dirmap_read)
                ret = ops->mem_ops->dirmap_read(desc, offs, len, buf);
        else
-               ret = -EOPNOTSUPP;
+               ret = -ENOTSUPP;
 
        return ret;
 }
@@ -847,7 +890,7 @@ ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc 
*desc,
        else if (ops->mem_ops && ops->mem_ops->dirmap_write)
                ret = ops->mem_ops->dirmap_write(desc, offs, len, buf);
        else
-               ret = -EOPNOTSUPP;
+               ret = -ENOTSUPP;
 
        return ret;
 }
diff --git a/include/spi-mem.h b/include/spi-mem.h
index 08d854b1e52..a69fd0d0948 100644
--- a/include/spi-mem.h
+++ b/include/spi-mem.h
@@ -22,10 +22,18 @@ struct udevice;
                .opcode = __opcode,                             \
        }
 
-#define SPI_MEM_DTR_OP_CMD(__opcode, __buswidth)               \
+#define SPI_MEM_DTR_OP_RPT_CMD(__opcode, __buswidth)           \
        {                                                       \
-               .nbytes = 1,                                    \
-               .opcode = __opcode,                             \
+               .nbytes = 2,                                    \
+               .opcode = __opcode | __opcode << 8,             \
+               .buswidth = __buswidth,                         \
+               .dtr = true,                                    \
+       }
+
+#define SPI_MEM_DTR_OP_PACKED_CMD(__opcode, __addr, __buswidth)        \
+       {                                                       \
+               .nbytes = 2,                                    \
+               .opcode = __opcode << 8 | __addr,               \
                .buswidth = __buswidth,                         \
                .dtr = true,                                    \
        }
@@ -45,6 +53,14 @@ struct udevice;
                .dtr = true,                                    \
        }
 
+#define SPI_MEM_DTR_OP_RPT_ADDR(__val, __buswidth)             \
+       {                                                       \
+               .nbytes = 2,                                    \
+               .val = __val | __val << 8,                      \
+               .buswidth = __buswidth,                         \
+               .dtr = true,                                    \
+       }
+
 #define SPI_MEM_OP_NO_ADDR     { }
 
 #define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)                 \
@@ -116,11 +132,13 @@ enum spi_mem_data_dir {
 
 /**
  * struct spi_mem_op - describes a SPI memory operation
+ * @cmd: the complete command
  * @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is
  *             sent MSB-first.
  * @cmd.buswidth: number of IO lines used to transmit the command
  * @cmd.opcode: operation opcode
  * @cmd.dtr: whether the command opcode should be sent in DTR mode or not
+ * @addr: the address attributes
  * @addr.nbytes: number of address bytes to send. Can be zero if the operation
  *              does not need to send an address
  * @addr.buswidth: number of IO lines used to transmit the address cycles
@@ -129,10 +147,12 @@ enum spi_mem_data_dir {
  *           Note that only @addr.nbytes are taken into account in this
  *           address value, so users should make sure the value fits in the
  *           assigned number of bytes.
+ * @dummy: data for dummy operation
  * @dummy.nbytes: number of dummy bytes to send after an opcode or address. Can
  *               be zero if the operation does not require dummy bytes
  * @dummy.buswidth: number of IO lanes used to transmit the dummy bytes
  * @dummy.dtr: whether the dummy bytes should be sent in DTR mode or not
+ * @data: the data attributes
  * @data.buswidth: number of IO lanes used to send/receive the data
  * @data.dtr: whether the data should be sent in DTR mode or not
  * @data.ecc: whether error correction is required or not
-- 
2.53.0

Reply via email to