diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 01:26:05 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 01:26:05 +0100 |
commit | b537149a2fb45ef9936b7a55aa801fbab8ea2a8a (patch) | |
tree | b0e53f0805bb5f943b8307d4389792ae24482883 /drivers/spi/spi-mem.c | |
parent | 6214a9fe2aeca5e22184b20954774424e2efc1f6 (diff) | |
parent | 7b9734dbc5b042bb8d8d930797f346b280057c4e (diff) |
Merge tag 'spi-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"One new core feature here, a small collection of new drivers and a
bunch of small improvements in existing drivers:
- A new CS_WORD flag for transfers where the chip select is toggled
at every word, with both a generic implementation and the ability
for controllers to do this automatically (including a DaVinci one).
- New drivers for Mediatek MT2712, Qualcomm GENI and QSPI, Spreadtrum
SPI and ST STM32 QSPI plus new IDs for several existing ones"
* tag 'spi-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (86 commits)
spi: lpspi: add imx8qxp compatible string
spi: Allow building SPI_BCM63XX_HSSPI on ARM-based SoCs
spi: omap2-mcspi: Add slave mode support
spi: omap2-mcspi: Set FIFO DMA trigger level to word length
spi: omap2-mcspi: Switch to readl_poll_timeout()
spi: spi-mem: add stm32 qspi controller
dt-bindings: spi: add stm32 qspi controller
spi: sh-msiof: document R8A779{7|8}0 bindings
spi: pic32-sqi: don't pass GFP_DMA32 to dma_alloc_coherent
MAINTAINERS: Add entry for Broadcom SPI controller
spi: sh-msiof: fix deferred probing
spi: imx: use PIO mode if size is small
spi: imx: correct wml as the last sg length
spi: imx: move wml setting to later than setup_transfer
PCI: Provide pci_match_id() with CONFIG_PCI=n
spi: Make GPIO CSs honour the SPI_NO_CS flag
spi/spi-pxa2xx: add PXA2xx SSP SPI Controller
spi: pxa2xx: Add devicetree support
spi: pxa2xx: Use an enum for type
spi: spi-geni-qcom: Add SPI driver support for GENI based QUP
...
Diffstat (limited to 'drivers/spi/spi-mem.c')
-rw-r--r-- | drivers/spi/spi-mem.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index e43842c7a31a..62a7b80801d2 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -12,6 +12,8 @@ #include "internals.h" +#define SPI_MEM_MAX_BUSWIDTH 4 + /** * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a * memory operation @@ -149,6 +151,44 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem, } 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) + 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_mem *mem, + const struct spi_mem_op *op) +{ + struct spi_controller *ctlr = mem->spi->controller; + + if (ctlr->mem_ops && ctlr->mem_ops->supports_op) + return ctlr->mem_ops->supports_op(mem, op); + + return spi_mem_default_supports_op(mem, op); +} + /** * spi_mem_supports_op() - Check if a memory device and the controller it is * connected to support a specific memory operation @@ -166,12 +206,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); */ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { - struct spi_controller *ctlr = mem->spi->controller; - - if (ctlr->mem_ops && ctlr->mem_ops->supports_op) - return ctlr->mem_ops->supports_op(mem, op); + if (spi_mem_check_op(op)) + return false; - return spi_mem_default_supports_op(mem, op); + return spi_mem_internal_supports_op(mem, op); } EXPORT_SYMBOL_GPL(spi_mem_supports_op); @@ -196,7 +234,11 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) u8 *tmpbuf; int ret; - if (!spi_mem_supports_op(mem, op)) + ret = spi_mem_check_op(op); + if (ret) + return ret; + + if (!spi_mem_internal_supports_op(mem, op)) return -ENOTSUPP; if (ctlr->mem_ops) { @@ -346,10 +388,25 @@ EXPORT_SYMBOL_GPL(spi_mem_get_name); int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { struct spi_controller *ctlr = mem->spi->controller; + size_t len; + + len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size) return ctlr->mem_ops->adjust_op_size(mem, op); + if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) { + if (len > spi_max_transfer_size(mem->spi)) + return -EINVAL; + + op->data.nbytes = min3((size_t)op->data.nbytes, + spi_max_transfer_size(mem->spi), + spi_max_message_size(mem->spi) - + len); + if (!op->data.nbytes) + return -EINVAL; + } + return 0; } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); |