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
