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 ++--------------------- include/uapi/linux/spi/spi.h | 31 +++++++++++++++++++++++++++++++ include/uapi/linux/spi/spidev.h | 30 +----------------------------- 3 files changed, 34 insertions(+), 50 deletions(-) create mode 100644 include/uapi/linux/spi/spi.h (limited to 'include') 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; diff --git a/include/uapi/linux/spi/spi.h b/include/uapi/linux/spi/spi.h new file mode 100644 index 000000000000..703b586f35df --- /dev/null +++ b/include/uapi/linux/spi/spi.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#ifndef _UAPI_SPI_H +#define _UAPI_SPI_H + +#include + +#define SPI_CPHA _BITUL(0) /* clock phase */ +#define SPI_CPOL _BITUL(1) /* 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 _BITUL(2) /* chipselect active high? */ +#define SPI_LSB_FIRST _BITUL(3) /* per-word bits-on-wire */ +#define SPI_3WIRE _BITUL(4) /* SI/SO signals shared */ +#define SPI_LOOP _BITUL(5) /* loopback mode */ +#define SPI_NO_CS _BITUL(6) /* 1 dev/bus, no chipselect */ +#define SPI_READY _BITUL(7) /* slave pulls low to pause */ +#define SPI_TX_DUAL _BITUL(8) /* transmit with 2 wires */ +#define SPI_TX_QUAD _BITUL(9) /* transmit with 4 wires */ +#define SPI_RX_DUAL _BITUL(10) /* receive with 2 wires */ +#define SPI_RX_QUAD _BITUL(11) /* receive with 4 wires */ +#define SPI_CS_WORD _BITUL(12) /* toggle cs after each word */ +#define SPI_TX_OCTAL _BITUL(13) /* transmit with 8 wires */ +#define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */ +#define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */ + +#endif /* _UAPI_SPI_H */ diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h index d56427c0b3e0..0c3da08f2aff 100644 --- a/include/uapi/linux/spi/spidev.h +++ b/include/uapi/linux/spi/spidev.h @@ -25,35 +25,7 @@ #include #include - -/* User space versions of kernel symbols for SPI clocking modes, - * matching - */ - -#define SPI_CPHA 0x01 -#define SPI_CPOL 0x02 - -#define SPI_MODE_0 (0|0) -#define SPI_MODE_1 (0|SPI_CPHA) -#define SPI_MODE_2 (SPI_CPOL|0) -#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) - -#define SPI_CS_HIGH 0x04 -#define SPI_LSB_FIRST 0x08 -#define SPI_3WIRE 0x10 -#define SPI_LOOP 0x20 -#define SPI_NO_CS 0x40 -#define SPI_READY 0x80 -#define SPI_TX_DUAL 0x100 -#define SPI_TX_QUAD 0x200 -#define SPI_RX_DUAL 0x400 -#define SPI_RX_QUAD 0x800 -#define SPI_CS_WORD 0x1000 -#define SPI_TX_OCTAL 0x2000 -#define SPI_RX_OCTAL 0x4000 -#define SPI_3WIRE_HIZ 0x8000 - -/*---------------------------------------------------------------------------*/ +#include /* IOCTL commands */ -- 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') 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 b499779761278d6f5339daa230938211d98861ef Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 21 Dec 2020 13:17:31 -0800 Subject: dt-bindings: clock: tegra: Add clock ID TEGRA210_CLK_QSPI_PM Tegra210 QSPI clock output has divider DIV2_SEL which will be enabled when using DDR interface mode. This patch adds clock ID for this to dt-binding. Acked-by: Rob Herring Signed-off-by: Sowjanya Komatineni Link: https://lore.kernel.org/r/1608585459-17250-2-git-send-email-skomatineni@nvidia.com Signed-off-by: Mark Brown --- include/dt-bindings/clock/tegra210-car.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h index ab8b8a737a0a..9cfcc3baa52c 100644 --- a/include/dt-bindings/clock/tegra210-car.h +++ b/include/dt-bindings/clock/tegra210-car.h @@ -307,7 +307,7 @@ #define TEGRA210_CLK_AUDIO4 275 #define TEGRA210_CLK_SPDIF 276 /* 277 */ -/* 278 */ +#define TEGRA210_CLK_QSPI_PM 278 /* 279 */ /* 280 */ #define TEGRA210_CLK_SOR0_LVDS 281 /* deprecated */ -- 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') 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 0ba882ae2818193487b70ad39622973538711d9a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 14 Jan 2021 16:16:27 +0100 Subject: spi: Drop unused efm32 bus driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for this machine was just removed, so drop the now unused spi bus driver, too. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20210114151630.128830-5-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 7 - drivers/spi/Makefile | 1 - drivers/spi/spi-efm32.c | 462 -------------------------------- include/linux/platform_data/efm32-spi.h | 15 -- 4 files changed, 485 deletions(-) delete mode 100644 drivers/spi/spi-efm32.c delete mode 100644 include/linux/platform_data/efm32-spi.h (limited to 'include') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index aadaea052f51..d3375aa6e292 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -292,13 +292,6 @@ config SPI_DLN2 This driver can also be built as a module. If so, the module will be called spi-dln2. -config SPI_EFM32 - tristate "EFM32 SPI controller" - depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST) - select SPI_BITBANG - help - Driver for the spi controller found on Energy Micro's EFM32 SoCs. - config SPI_EP93XX tristate "Cirrus Logic EP93xx SPI controller" depends on ARCH_EP93XX || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6fea5821662e..5a21b5cc8015 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -42,7 +42,6 @@ spi-dw-$(CONFIG_SPI_DW_DMA) += spi-dw-dma.o obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.o obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o -obj-$(CONFIG_SPI_EFM32) += spi-efm32.o obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o obj-$(CONFIG_SPI_FALCON) += spi-falcon.o obj-$(CONFIG_SPI_FSI) += spi-fsi.o diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c deleted file mode 100644 index ea6e4a7b3feb..000000000000 --- a/drivers/spi/spi-efm32.c +++ /dev/null @@ -1,462 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2012-2013 Uwe Kleine-Koenig for Pengutronix - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "efm32-spi" - -#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask) - -#define REG_CTRL 0x00 -#define REG_CTRL_SYNC 0x0001 -#define REG_CTRL_CLKPOL 0x0100 -#define REG_CTRL_CLKPHA 0x0200 -#define REG_CTRL_MSBF 0x0400 -#define REG_CTRL_TXBIL 0x1000 - -#define REG_FRAME 0x04 -#define REG_FRAME_DATABITS__MASK 0x000f -#define REG_FRAME_DATABITS(n) ((n) - 3) - -#define REG_CMD 0x0c -#define REG_CMD_RXEN 0x0001 -#define REG_CMD_RXDIS 0x0002 -#define REG_CMD_TXEN 0x0004 -#define REG_CMD_TXDIS 0x0008 -#define REG_CMD_MASTEREN 0x0010 - -#define REG_STATUS 0x10 -#define REG_STATUS_TXENS 0x0002 -#define REG_STATUS_TXC 0x0020 -#define REG_STATUS_TXBL 0x0040 -#define REG_STATUS_RXDATAV 0x0080 - -#define REG_CLKDIV 0x14 - -#define REG_RXDATAX 0x18 -#define REG_RXDATAX_RXDATA__MASK 0x01ff -#define REG_RXDATAX_PERR 0x4000 -#define REG_RXDATAX_FERR 0x8000 - -#define REG_TXDATA 0x34 - -#define REG_IF 0x40 -#define REG_IF_TXBL 0x0002 -#define REG_IF_RXDATAV 0x0004 - -#define REG_IFS 0x44 -#define REG_IFC 0x48 -#define REG_IEN 0x4c - -#define REG_ROUTE 0x54 -#define REG_ROUTE_RXPEN 0x0001 -#define REG_ROUTE_TXPEN 0x0002 -#define REG_ROUTE_CLKPEN 0x0008 -#define REG_ROUTE_LOCATION__MASK 0x0700 -#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n)) - -struct efm32_spi_ddata { - struct spi_bitbang bitbang; - - spinlock_t lock; - - struct clk *clk; - void __iomem *base; - unsigned int rxirq, txirq; - struct efm32_spi_pdata pdata; - - /* irq data */ - struct completion done; - const u8 *tx_buf; - u8 *rx_buf; - unsigned tx_len, rx_len; -}; - -#define ddata_to_dev(ddata) (&(ddata->bitbang.master->dev)) -#define efm32_spi_vdbg(ddata, format, arg...) \ - dev_vdbg(ddata_to_dev(ddata), format, ##arg) - -static void efm32_spi_write32(struct efm32_spi_ddata *ddata, - u32 value, unsigned offset) -{ - writel_relaxed(value, ddata->base + offset); -} - -static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset) -{ - return readl_relaxed(ddata->base + offset); -} - -static int efm32_spi_setup_transfer(struct spi_device *spi, - struct spi_transfer *t) -{ - struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master); - - unsigned bpw = t->bits_per_word ?: spi->bits_per_word; - unsigned speed = t->speed_hz ?: spi->max_speed_hz; - unsigned long clkfreq = clk_get_rate(ddata->clk); - u32 clkdiv; - - efm32_spi_write32(ddata, REG_CTRL_SYNC | REG_CTRL_MSBF | - (spi->mode & SPI_CPHA ? REG_CTRL_CLKPHA : 0) | - (spi->mode & SPI_CPOL ? REG_CTRL_CLKPOL : 0), REG_CTRL); - - efm32_spi_write32(ddata, - REG_FRAME_DATABITS(bpw), REG_FRAME); - - if (2 * speed >= clkfreq) - clkdiv = 0; - else - clkdiv = 64 * (DIV_ROUND_UP(2 * clkfreq, speed) - 4); - - if (clkdiv > (1U << 21)) - return -EINVAL; - - efm32_spi_write32(ddata, clkdiv, REG_CLKDIV); - efm32_spi_write32(ddata, REG_CMD_MASTEREN, REG_CMD); - efm32_spi_write32(ddata, REG_CMD_RXEN | REG_CMD_TXEN, REG_CMD); - - return 0; -} - -static void efm32_spi_tx_u8(struct efm32_spi_ddata *ddata) -{ - u8 val = 0; - - if (ddata->tx_buf) { - val = *ddata->tx_buf; - ddata->tx_buf++; - } - - ddata->tx_len--; - efm32_spi_write32(ddata, val, REG_TXDATA); - efm32_spi_vdbg(ddata, "%s: tx 0x%x\n", __func__, val); -} - -static void efm32_spi_rx_u8(struct efm32_spi_ddata *ddata) -{ - u32 rxdata = efm32_spi_read32(ddata, REG_RXDATAX); - efm32_spi_vdbg(ddata, "%s: rx 0x%x\n", __func__, rxdata); - - if (ddata->rx_buf) { - *ddata->rx_buf = rxdata; - ddata->rx_buf++; - } - - ddata->rx_len--; -} - -static void efm32_spi_filltx(struct efm32_spi_ddata *ddata) -{ - while (ddata->tx_len && - ddata->tx_len + 2 > ddata->rx_len && - efm32_spi_read32(ddata, REG_STATUS) & REG_STATUS_TXBL) { - efm32_spi_tx_u8(ddata); - } -} - -static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) -{ - struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master); - int ret = -EBUSY; - - spin_lock_irq(&ddata->lock); - - if (ddata->tx_buf || ddata->rx_buf) - goto out_unlock; - - ddata->tx_buf = t->tx_buf; - ddata->rx_buf = t->rx_buf; - ddata->tx_len = ddata->rx_len = - t->len * DIV_ROUND_UP(t->bits_per_word, 8); - - efm32_spi_filltx(ddata); - - reinit_completion(&ddata->done); - - efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN); - - spin_unlock_irq(&ddata->lock); - - wait_for_completion(&ddata->done); - - spin_lock_irq(&ddata->lock); - - ret = t->len - max(ddata->tx_len, ddata->rx_len); - - efm32_spi_write32(ddata, 0, REG_IEN); - ddata->tx_buf = ddata->rx_buf = NULL; - -out_unlock: - spin_unlock_irq(&ddata->lock); - - return ret; -} - -static irqreturn_t efm32_spi_rxirq(int irq, void *data) -{ - struct efm32_spi_ddata *ddata = data; - irqreturn_t ret = IRQ_NONE; - - spin_lock(&ddata->lock); - - while (ddata->rx_len > 0 && - efm32_spi_read32(ddata, REG_STATUS) & - REG_STATUS_RXDATAV) { - efm32_spi_rx_u8(ddata); - - ret = IRQ_HANDLED; - } - - if (!ddata->rx_len) { - u32 ien = efm32_spi_read32(ddata, REG_IEN); - - ien &= ~REG_IF_RXDATAV; - - efm32_spi_write32(ddata, ien, REG_IEN); - - complete(&ddata->done); - } - - spin_unlock(&ddata->lock); - - return ret; -} - -static irqreturn_t efm32_spi_txirq(int irq, void *data) -{ - struct efm32_spi_ddata *ddata = data; - - efm32_spi_vdbg(ddata, - "%s: txlen = %u, rxlen = %u, if=0x%08x, stat=0x%08x\n", - __func__, ddata->tx_len, ddata->rx_len, - efm32_spi_read32(ddata, REG_IF), - efm32_spi_read32(ddata, REG_STATUS)); - - spin_lock(&ddata->lock); - - efm32_spi_filltx(ddata); - - efm32_spi_vdbg(ddata, "%s: txlen = %u, rxlen = %u\n", - __func__, ddata->tx_len, ddata->rx_len); - - if (!ddata->tx_len) { - u32 ien = efm32_spi_read32(ddata, REG_IEN); - - ien &= ~REG_IF_TXBL; - - efm32_spi_write32(ddata, ien, REG_IEN); - efm32_spi_vdbg(ddata, "disable TXBL\n"); - } - - spin_unlock(&ddata->lock); - - return IRQ_HANDLED; -} - -static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata) -{ - u32 reg = efm32_spi_read32(ddata, REG_ROUTE); - - return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK); -} - -static void efm32_spi_probe_dt(struct platform_device *pdev, - struct spi_master *master, struct efm32_spi_ddata *ddata) -{ - struct device_node *np = pdev->dev.of_node; - u32 location; - int ret; - - ret = of_property_read_u32(np, "energymicro,location", &location); - - if (ret) - /* fall back to wrongly namespaced property */ - ret = of_property_read_u32(np, "efm32,location", &location); - - if (ret) - /* fall back to old and (wrongly) generic property "location" */ - ret = of_property_read_u32(np, "location", &location); - - if (!ret) { - dev_dbg(&pdev->dev, "using location %u\n", location); - } else { - /* default to location configured in hardware */ - location = efm32_spi_get_configured_location(ddata); - - dev_info(&pdev->dev, "fall back to location %u\n", location); - } - - ddata->pdata.location = location; -} - -static int efm32_spi_probe(struct platform_device *pdev) -{ - struct efm32_spi_ddata *ddata; - struct resource *res; - int ret; - struct spi_master *master; - struct device_node *np = pdev->dev.of_node; - - if (!np) - return -EINVAL; - - master = spi_alloc_master(&pdev->dev, sizeof(*ddata)); - if (!master) { - dev_dbg(&pdev->dev, - "failed to allocate spi master controller\n"); - return -ENOMEM; - } - platform_set_drvdata(pdev, master); - - master->dev.of_node = pdev->dev.of_node; - - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); - master->use_gpio_descriptors = true; - - ddata = spi_master_get_devdata(master); - - ddata->bitbang.master = master; - ddata->bitbang.setup_transfer = efm32_spi_setup_transfer; - ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs; - - spin_lock_init(&ddata->lock); - init_completion(&ddata->done); - - ddata->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(ddata->clk)) { - ret = PTR_ERR(ddata->clk); - dev_err(&pdev->dev, "failed to get clock: %d\n", ret); - goto err; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_err(&pdev->dev, "failed to determine base address\n"); - goto err; - } - - if (resource_size(res) < 0x60) { - ret = -EINVAL; - dev_err(&pdev->dev, "memory resource too small\n"); - goto err; - } - - ddata->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ddata->base)) { - ret = PTR_ERR(ddata->base); - goto err; - } - - ret = platform_get_irq(pdev, 0); - if (ret <= 0) - goto err; - - ddata->rxirq = ret; - - ret = platform_get_irq(pdev, 1); - if (ret <= 0) - ret = ddata->rxirq + 1; - - ddata->txirq = ret; - - ret = clk_prepare_enable(ddata->clk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret); - goto err; - } - - efm32_spi_probe_dt(pdev, master, ddata); - - efm32_spi_write32(ddata, 0, REG_IEN); - efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN | - REG_ROUTE_CLKPEN | - REG_ROUTE_LOCATION(ddata->pdata.location), REG_ROUTE); - - ret = request_irq(ddata->rxirq, efm32_spi_rxirq, - 0, DRIVER_NAME " rx", ddata); - if (ret) { - dev_err(&pdev->dev, "failed to register rxirq (%d)\n", ret); - goto err_disable_clk; - } - - ret = request_irq(ddata->txirq, efm32_spi_txirq, - 0, DRIVER_NAME " tx", ddata); - if (ret) { - dev_err(&pdev->dev, "failed to register txirq (%d)\n", ret); - goto err_free_rx_irq; - } - - ret = spi_bitbang_start(&ddata->bitbang); - if (ret) { - dev_err(&pdev->dev, "spi_bitbang_start failed (%d)\n", ret); - - free_irq(ddata->txirq, ddata); -err_free_rx_irq: - free_irq(ddata->rxirq, ddata); -err_disable_clk: - clk_disable_unprepare(ddata->clk); -err: - spi_master_put(master); - } - - return ret; -} - -static int efm32_spi_remove(struct platform_device *pdev) -{ - struct spi_master *master = platform_get_drvdata(pdev); - struct efm32_spi_ddata *ddata = spi_master_get_devdata(master); - - spi_bitbang_stop(&ddata->bitbang); - - efm32_spi_write32(ddata, 0, REG_IEN); - - free_irq(ddata->txirq, ddata); - free_irq(ddata->rxirq, ddata); - clk_disable_unprepare(ddata->clk); - spi_master_put(master); - - return 0; -} - -static const struct of_device_id efm32_spi_dt_ids[] = { - { - .compatible = "energymicro,efm32-spi", - }, { - /* doesn't follow the "vendor,device" scheme, don't use */ - .compatible = "efm32,spi", - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(of, efm32_spi_dt_ids); - -static struct platform_driver efm32_spi_driver = { - .probe = efm32_spi_probe, - .remove = efm32_spi_remove, - - .driver = { - .name = DRIVER_NAME, - .of_match_table = efm32_spi_dt_ids, - }, -}; -module_platform_driver(efm32_spi_driver); - -MODULE_AUTHOR("Uwe Kleine-Koenig "); -MODULE_DESCRIPTION("EFM32 SPI driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/include/linux/platform_data/efm32-spi.h b/include/linux/platform_data/efm32-spi.h deleted file mode 100644 index a2c56fcd0534..000000000000 --- a/include/linux/platform_data/efm32-spi.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_PLATFORM_DATA_EFM32_SPI_H__ -#define __LINUX_PLATFORM_DATA_EFM32_SPI_H__ - -#include - -/** - * struct efm32_spi_pdata - * @location: pinmux location for the I/O pins (to be written to the ROUTE - * register) - */ -struct efm32_spi_pdata { - u8 location; -}; -#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_SPI_H__ */ -- 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') 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') 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