From f7005142dacea1769fba0152c493aaa61b33205c Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 21 Dec 2020 17:29:34 +0200 Subject: spi: uapi: unify SPI modes into a single spi.h header This change moves all the SPI mode bits into a separate 'spi.h' header in uAPI. This is meant to re-use these definitions inside the kernel as well as export them to userspace (via uAPI). The SPI mode definitions have usually been duplicated between between 'include/linux/spi/spi.h' and 'include/uapi/linux/spi/spidev.h', so whenever adding a new entry, this would need to be put in both headers. They've been moved from 'include/linux/spi/spi.h', since that seems a bit more complete; the bits have descriptions and there is the SPI_MODE_X_MASK. This change also does a conversion of these bitfields to _BITUL() macro. Reviewed-by: Andy Shevchenko Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201221152936.53873-1-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'include/linux/spi') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index aa09fdc8042d..a08c3f37e202 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -15,6 +15,8 @@ #include #include +#include + struct dma_chan; struct property_entry; struct spi_controller; @@ -165,27 +167,6 @@ struct spi_device { u8 bits_per_word; bool rt; u32 mode; -#define SPI_CPHA 0x01 /* clock phase */ -#define SPI_CPOL 0x02 /* clock polarity */ -#define SPI_MODE_0 (0|0) /* (original MicroWire) */ -#define SPI_MODE_1 (0|SPI_CPHA) -#define SPI_MODE_2 (SPI_CPOL|0) -#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) -#define SPI_MODE_X_MASK (SPI_CPOL|SPI_CPHA) -#define SPI_CS_HIGH 0x04 /* chipselect active high? */ -#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ -#define SPI_3WIRE 0x10 /* SI/SO signals shared */ -#define SPI_LOOP 0x20 /* loopback mode */ -#define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */ -#define SPI_READY 0x80 /* slave pulls low to pause */ -#define SPI_TX_DUAL 0x100 /* transmit with 2 wires */ -#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */ -#define SPI_RX_DUAL 0x400 /* receive with 2 wires */ -#define SPI_RX_QUAD 0x800 /* receive with 4 wires */ -#define SPI_CS_WORD 0x1000 /* toggle cs after each word */ -#define SPI_TX_OCTAL 0x2000 /* transmit with 8 wires */ -#define SPI_RX_OCTAL 0x4000 /* receive with 8 wires */ -#define SPI_3WIRE_HIZ 0x8000 /* high impedance turnaround */ int irq; void *controller_state; void *controller_data; -- cgit v1.2.3 From d962608ce2188a1d46ec9d356d6fad5cd6fc0341 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Mon, 21 Dec 2020 17:29:35 +0200 Subject: spi: Add SPI_NO_TX/RX support Transmit/receive only is a valid SPI mode. For example, the MOSI/TX line might be missing from an ADC while for a DAC the MISO/RX line may be optional. This patch adds these two new modes: SPI_NO_TX and SPI_NO_RX. This way, the drivers will be able to identify if any of these two lines is missing and to adjust the transfers accordingly. Signed-off-by: Dragos Bogdan Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201221152936.53873-2-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 25 ++++++++++++++++++++----- include/linux/spi/spi.h | 17 +++++++++++++++++ include/uapi/linux/spi/spi.h | 10 ++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) (limited to 'include/linux/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 51d7c004fbab..ca75f4036eda 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1941,6 +1941,9 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, /* Device DUAL/QUAD mode */ if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { switch (value) { + case 0: + spi->mode |= SPI_NO_TX; + break; case 1: break; case 2: @@ -1962,6 +1965,9 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) { switch (value) { + case 0: + spi->mode |= SPI_NO_RX; + break; case 1: break; case 2: @@ -3329,12 +3335,16 @@ int spi_setup(struct spi_device *spi) unsigned bad_bits, ugly_bits; int status; - /* check mode to prevent that DUAL and QUAD set at the same time + /* + * check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO + * are set at the same time */ - if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) || - ((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) { + if ((hweight_long(spi->mode & + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_NO_TX)) > 1) || + (hweight_long(spi->mode & + (SPI_RX_DUAL | SPI_RX_QUAD | SPI_NO_RX)) > 1)) { dev_err(&spi->dev, - "setup: can not select dual and quad at the same time\n"); + "setup: can not select any two of dual, quad and no-rx/tx at the same time\n"); return -EINVAL; } /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden @@ -3348,7 +3358,8 @@ int spi_setup(struct spi_device *spi) * SPI_CS_WORD has a fallback software implementation, * so it is ignored here. */ - bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD); + bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD | + SPI_NO_TX | SPI_NO_RX); /* nothing prevents from working with active-high CS in case if it * is driven by GPIO. */ @@ -3610,6 +3621,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) * 2. check tx/rx_nbits match the mode in spi_device */ if (xfer->tx_buf) { + if (spi->mode & SPI_NO_TX) + return -EINVAL; if (xfer->tx_nbits != SPI_NBITS_SINGLE && xfer->tx_nbits != SPI_NBITS_DUAL && xfer->tx_nbits != SPI_NBITS_QUAD) @@ -3623,6 +3636,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) } /* check transfer rx_nbits */ if (xfer->rx_buf) { + if (spi->mode & SPI_NO_RX) + return -EINVAL; if (xfer->rx_nbits != SPI_NBITS_SINGLE && xfer->rx_nbits != SPI_NBITS_DUAL && xfer->rx_nbits != SPI_NBITS_QUAD) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index a08c3f37e202..9bfdfaf286eb 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -6,6 +6,7 @@ #ifndef __LINUX_SPI_H #define __LINUX_SPI_H +#include #include #include #include @@ -166,6 +167,18 @@ struct spi_device { u8 chip_select; u8 bits_per_word; bool rt; +#define SPI_NO_TX BIT(31) /* no transmit wire */ +#define SPI_NO_RX BIT(30) /* no receive wire */ + /* + * All bits defined above should be covered by SPI_MODE_KERNEL_MASK. + * The SPI_MODE_KERNEL_MASK has the SPI_MODE_USER_MASK counterpart, + * which is defined in 'include/uapi/linux/spi/spi.h'. + * The bits defined here are from bit 31 downwards, while in + * SPI_MODE_USER_MASK are from 0 upwards. + * These bits must not overlap. A static assert check should make sure of that. + * If adding extra bits, make sure to decrease the bit index below as well. + */ +#define SPI_MODE_KERNEL_MASK (~(BIT(30) - 1)) u32 mode; int irq; void *controller_state; @@ -189,6 +202,10 @@ struct spi_device { */ }; +/* Make sure that SPI_MODE_KERNEL_MASK & SPI_MODE_USER_MASK don't overlap */ +static_assert((SPI_MODE_KERNEL_MASK & SPI_MODE_USER_MASK) == 0, + "SPI_MODE_USER_MASK & SPI_MODE_KERNEL_MASK must not overlap"); + static inline struct spi_device *to_spi_device(struct device *dev) { return dev ? container_of(dev, struct spi_device, dev) : NULL; diff --git a/include/uapi/linux/spi/spi.h b/include/uapi/linux/spi/spi.h index 703b586f35df..236a85f08ded 100644 --- a/include/uapi/linux/spi/spi.h +++ b/include/uapi/linux/spi/spi.h @@ -28,4 +28,14 @@ #define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */ #define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */ +/* + * All the bits defined above should be covered by SPI_MODE_USER_MASK. + * The SPI_MODE_USER_MASK has the SPI_MODE_KERNEL_MASK counterpart in + * 'include/linux/spi/spi.h'. The bits defined here are from bit 0 upwards + * while in SPI_MODE_KERNEL_MASK they are from the other end downwards. + * These bits must not overlap. A static assert check should make sure of that. + * If adding extra bits, make sure to increase the bit index below as well. + */ +#define SPI_MODE_USER_MASK (_BITUL(16) - 1) + #endif /* _UAPI_SPI_H */ -- cgit v1.2.3 From 98621ed011c57ba6e52e01a5982b221c9943b6d9 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 21 Dec 2020 13:17:35 -0800 Subject: spi: spi-mem: Mark dummy transfers by setting dummy_data bit This patch marks dummy transfer by setting dummy_data bit to 1. Controllers supporting dummy transfer by hardware use this bit field to skip software transfer of dummy bytes and use hardware dummy bytes transfer. Signed-off-by: Sowjanya Komatineni Link: https://lore.kernel.org/r/1608585459-17250-6-git-send-email-skomatineni@nvidia.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 1 + include/linux/spi/spi.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'include/linux/spi') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index f3a3f196e628..c64371ce6c38 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -354,6 +354,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1; xfers[xferpos].len = op->dummy.nbytes; xfers[xferpos].tx_nbits = op->dummy.buswidth; + xfers[xferpos].dummy_data = 1; spi_message_add_tail(&xfers[xferpos], &msg); xferpos++; totalxferlen += op->dummy.nbytes; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 9bfdfaf286eb..797ef28fa7d5 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -825,6 +825,7 @@ extern void spi_res_release(struct spi_controller *ctlr, * transfer. If 0 the default (from @spi_device) is used. * @bits_per_word: select a bits_per_word other than the device default * for this transfer. If 0 the default (from @spi_device) is used. + * @dummy_data: indicates transfer is dummy bytes transfer. * @cs_change: affects chipselect after this transfer completes * @cs_change_delay: delay between cs deassert and assert when * @cs_change is set and @spi_transfer is not the last in @spi_message @@ -937,6 +938,7 @@ struct spi_transfer { struct sg_table tx_sg; struct sg_table rx_sg; + unsigned dummy_data:1; unsigned cs_change:1; unsigned tx_nbits:3; unsigned rx_nbits:3; -- cgit v1.2.3 From 883c36a32fc031046218ef5802023d5aa54d6cb0 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Mon, 8 Feb 2021 17:19:28 +0530 Subject: spi: Change provied to provided in the file spi.h s/provied/provided/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210208114928.32241-1-unixbhaskar@gmail.com Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/spi') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 797ef28fa7d5..592897fa4f03 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -622,7 +622,7 @@ struct spi_controller { /* * These hooks are for drivers that use a generic implementation - * of transfer_one_message() provied by the core. + * of transfer_one_message() provided by the core. */ void (*set_cs)(struct spi_device *spi, bool enable); int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi, -- cgit v1.2.3 From 539cf68cd51bfcd2987ce1c44e628e9da69de7c8 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Thu, 4 Feb 2021 19:42:17 +0530 Subject: spi: spi-mem: add spi_mem_dtr_supports_op() spi_mem_default_supports_op() rejects DTR ops by default to ensure that the controller drivers that haven't been updated with DTR support continue to reject them. It also makes sure that controllers that don't support DTR mode at all (which is most of them at the moment) also reject them. This means that controller drivers that want to support DTR mode can't use spi_mem_default_supports_op(). Driver authors have to roll their own supports_op() function and mimic the buswidth checks. See spi-cadence-quadspi.c for example. Or even worse, driver authors might skip it completely or get it wrong. Add spi_mem_dtr_supports_op(). It provides a basic sanity check for DTR ops and performs the buswidth requirement check. Move the logic for checking buswidth in spi_mem_default_supports_op() to a separate function so the logic is not repeated twice. Signed-off-by: Pratyush Yadav Reviewed-by: Miquel Raynal Link: https://lore.kernel.org/r/20210204141218.32229-1-p.yadav@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 22 +++++++++++++++++++--- include/linux/spi/spi-mem.h | 9 +++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'include/linux/spi') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index c64371ce6c38..dc713b0c3c4d 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -137,8 +137,8 @@ static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx) return -ENOTSUPP; } -bool spi_mem_default_supports_op(struct spi_mem *mem, - const struct spi_mem_op *op) +static bool spi_mem_check_buswidth(struct spi_mem *mem, + const struct spi_mem_op *op) { if (spi_check_buswidth_req(mem, op->cmd.buswidth, true)) return false; @@ -156,13 +156,29 @@ bool spi_mem_default_supports_op(struct spi_mem *mem, op->data.dir == SPI_MEM_DATA_OUT)) return false; + return true; +} + +bool spi_mem_dtr_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (op->cmd.nbytes != 2) + return false; + + return spi_mem_check_buswidth(mem, op); +} +EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op); + +bool spi_mem_default_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) return false; if (op->cmd.nbytes != 1) return false; - return true; + return spi_mem_check_buswidth(mem, op); } EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index 159463cc659c..2b65c9edc34e 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -311,6 +311,9 @@ void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr, bool spi_mem_default_supports_op(struct spi_mem *mem, const struct spi_mem_op *op); +bool spi_mem_dtr_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op); + #else static inline int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr, @@ -334,6 +337,12 @@ bool spi_mem_default_supports_op(struct spi_mem *mem, return false; } +static inline +bool spi_mem_dtr_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + return false; +} #endif /* CONFIG_SPI_MEM */ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op); -- cgit v1.2.3