aboutsummaryrefslogtreecommitdiff
path: root/tools/perf/scripts/python/bin/stackcollapse-report
blob: 356b9656393db5a59bb3083d79d0ab0c35e1200a (plain)
1
2
3
#!/bin/sh
# description: produce callgraphs in short form for scripting use
perf script -s "$PERF_EXEC_PATH"/scripts/python/stackcollapse.py -- "$@"
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(-) 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 ffe9819b6766b9a623822f3427df4953ab448127 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 21 Dec 2020 17:29:36 +0200 Subject: spi: dt-bindings: document zero value for spi-{rx,tx}-bus-width properties Following a change to the SPI framework, providing a value of zero for 'spi-rx-bus-width' and 'spi-tx-bus-width' is now possible and will essentially mean that no RX or TX is allowed. Reviewed-by: Rob Herring Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201221152936.53873-3-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-controller.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml index 5f505810104d..06786f1b43d2 100644 --- a/Documentation/devicetree/bindings/spi/spi-controller.yaml +++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml @@ -152,8 +152,9 @@ patternProperties: spi-rx-bus-width: description: Bus width to the SPI bus used for read transfers. + If 0 is provided, then no RX will be possible on this device. $ref: /schemas/types.yaml#/definitions/uint32 - enum: [1, 2, 4, 8] + enum: [0, 1, 2, 4, 8] default: 1 spi-rx-delay-us: @@ -163,8 +164,9 @@ patternProperties: spi-tx-bus-width: description: Bus width to the SPI bus used for write transfers. + If 0 is provided, then no TX will be possible on this device. $ref: /schemas/types.yaml#/definitions/uint32 - enum: [1, 2, 4, 8] + enum: [0, 1, 2, 4, 8] default: 1 spi-tx-delay-us: -- cgit v1.2.3 From 9584fc95cadc0b86e5e01cefcff0ab2b31ee3a5b Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 30 Dec 2020 14:57:08 +0000 Subject: spi: rpc-if: Remove CONFIG_PM_SLEEP ifdefery Use __maybe_unused for the suspend()/resume() hooks and get rid of the CONFIG_PM_SLEEP ifdefery to improve the code. Suggested-by: Pavel Machek Signed-off-by: Lad Prabhakar Acked-by: Pavel Machek Link: https://lore.kernel.org/r/20201230145708.28544-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi-rpc-if.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index 3579675485a5..c313dbe6185c 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -176,15 +176,14 @@ static int rpcif_spi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int rpcif_spi_suspend(struct device *dev) +static int __maybe_unused rpcif_spi_suspend(struct device *dev) { struct spi_controller *ctlr = dev_get_drvdata(dev); return spi_controller_suspend(ctlr); } -static int rpcif_spi_resume(struct device *dev) +static int __maybe_unused rpcif_spi_resume(struct device *dev) { struct spi_controller *ctlr = dev_get_drvdata(dev); @@ -192,17 +191,13 @@ static int rpcif_spi_resume(struct device *dev) } static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume); -#define DEV_PM_OPS (&rpcif_spi_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif static struct platform_driver rpcif_spi_driver = { .probe = rpcif_spi_probe, .remove = rpcif_spi_remove, .driver = { .name = "rpc-if-spi", - .pm = DEV_PM_OPS, + .pm = &rpcif_spi_pm_ops, }, }; module_platform_driver(rpcif_spi_driver); -- cgit v1.2.3 From f4a10fc4225155ae4d2fcb411be9f24245bb5cf8 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Sat, 2 Jan 2021 05:54:11 -0600 Subject: spi: renesas rpc-if: Update Add RZ/G2 to Kconfig description The SPI driver for the Renesas RPC-IF is present on the RZ/G2 Series. Add that to the description. Suggested-by: Biju Das Signed-off-by: Adam Ford Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20210102115412.3402059-3-aford173@gmail.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index aadaea052f51..e0eb2093aca6 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -650,7 +650,7 @@ config SPI_RPCIF tristate "Renesas RPC-IF SPI driver" depends on RENESAS_RPCIF help - SPI driver for Renesas R-Car Gen3 RPC-IF. + SPI driver for Renesas R-Car Gen3 or RZ/G2 RPC-IF. config SPI_RSPI tristate "Renesas RSPI/QSPI controller" -- cgit v1.2.3 From 8b835da61774d4482864bc081dfb428104842ad3 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 4 Jan 2021 16:31:03 +0200 Subject: spi: stm32: update dev_dbg() print format for SPI params With the introduction of the 'include/uapi/linux/spi/spi.h' header, the type of the macros are enforced to 'unsigned long int' via the _BITUL() macro. This causes some -Wformat warnings in the spi-stm32 driver. This patch adds a double-negation operator to the bit-masks. Essentially, the important values for debugging are 0 or 1, while masking them directly would show 0 or BIT(x) values. This way, the type of the arguments are automatically re-cast. Fixes: f7005142dace ("spi: uapi: unify SPI modes into a single spi.h header") Reported-by: kernel test robot Reported-by: Stephen Rothwell Cc: Andy Shevchenko Signed-off-by: Alexandru Ardelean Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210104143103.56510-1-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 6017209c6d2f..be0fb169d7a7 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1028,10 +1028,10 @@ static int stm32_spi_prepare_msg(struct spi_master *master, clrb |= spi->cfg->regs->lsb_first.mask; dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n", - spi_dev->mode & SPI_CPOL, - spi_dev->mode & SPI_CPHA, - spi_dev->mode & SPI_LSB_FIRST, - spi_dev->mode & SPI_CS_HIGH); + !!(spi_dev->mode & SPI_CPOL), + !!(spi_dev->mode & SPI_CPHA), + !!(spi_dev->mode & SPI_LSB_FIRST), + !!(spi_dev->mode & SPI_CS_HIGH)); spin_lock_irqsave(&spi->lock, flags); -- cgit v1.2.3 From 74523a5dae0c96d6503fe72da66ee37fd23eb8f5 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Tue, 5 Jan 2021 15:02:49 +0100 Subject: spi: txx9: Remove driver CPU support for TX49xx is getting removed, so remove support SPI driver for it. Signed-off-by: Thomas Bogendoerfer Link: https://lore.kernel.org/r/20210105140305.141401-5-tsbogend@alpha.franken.de Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 6 - drivers/spi/Makefile | 1 - drivers/spi/spi-txx9.c | 477 ------------------------------------------------- 3 files changed, 484 deletions(-) delete mode 100644 drivers/spi/spi-txx9.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e0eb2093aca6..45f5c80cb3e0 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -885,12 +885,6 @@ config SPI_TOPCLIFF_PCH This driver also supports the ML7213/ML7223/ML7831, a companion chip for the Atom E6xx series and compatible with the Intel EG20T PCH. -config SPI_TXX9 - tristate "Toshiba TXx9 SPI controller" - depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST) - help - SPI driver for Toshiba TXx9 MIPS SoCs - config SPI_UNIPHIER tristate "Socionext UniPhier SPI Controller" depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6fea5821662e..9578b40e7800 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -122,7 +122,6 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o -obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_UNIPHIER) += spi-uniphier.o obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c deleted file mode 100644 index 3606232f190f..000000000000 --- a/drivers/spi/spi-txx9.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * TXx9 SPI controller driver. - * - * Based on linux/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c - * Copyright (C) 2000-2001 Toshiba Corporation - * - * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is - * licensed "as is" without any warranty of any kind, whether express - * or implied. - * - * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) - * - * Convert to generic SPI framework - Atsushi Nemoto (anemo@mba.ocn.ne.jp) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define SPI_FIFO_SIZE 4 -#define SPI_MAX_DIVIDER 0xff /* Max. value for SPCR1.SER */ -#define SPI_MIN_DIVIDER 1 /* Min. value for SPCR1.SER */ - -#define TXx9_SPMCR 0x00 -#define TXx9_SPCR0 0x04 -#define TXx9_SPCR1 0x08 -#define TXx9_SPFS 0x0c -#define TXx9_SPSR 0x14 -#define TXx9_SPDR 0x18 - -/* SPMCR : SPI Master Control */ -#define TXx9_SPMCR_OPMODE 0xc0 -#define TXx9_SPMCR_CONFIG 0x40 -#define TXx9_SPMCR_ACTIVE 0x80 -#define TXx9_SPMCR_SPSTP 0x02 -#define TXx9_SPMCR_BCLR 0x01 - -/* SPCR0 : SPI Control 0 */ -#define TXx9_SPCR0_TXIFL_MASK 0xc000 -#define TXx9_SPCR0_RXIFL_MASK 0x3000 -#define TXx9_SPCR0_SIDIE 0x0800 -#define TXx9_SPCR0_SOEIE 0x0400 -#define TXx9_SPCR0_RBSIE 0x0200 -#define TXx9_SPCR0_TBSIE 0x0100 -#define TXx9_SPCR0_IFSPSE 0x0010 -#define TXx9_SPCR0_SBOS 0x0004 -#define TXx9_SPCR0_SPHA 0x0002 -#define TXx9_SPCR0_SPOL 0x0001 - -/* SPSR : SPI Status */ -#define TXx9_SPSR_TBSI 0x8000 -#define TXx9_SPSR_RBSI 0x4000 -#define TXx9_SPSR_TBS_MASK 0x3800 -#define TXx9_SPSR_RBS_MASK 0x0700 -#define TXx9_SPSR_SPOE 0x0080 -#define TXx9_SPSR_IFSD 0x0008 -#define TXx9_SPSR_SIDLE 0x0004 -#define TXx9_SPSR_STRDY 0x0002 -#define TXx9_SPSR_SRRDY 0x0001 - - -struct txx9spi { - struct work_struct work; - spinlock_t lock; /* protect 'queue' */ - struct list_head queue; - wait_queue_head_t waitq; - void __iomem *membase; - int baseclk; - struct clk *clk; - struct gpio_desc *last_chipselect; - int last_chipselect_val; -}; - -static u32 txx9spi_rd(struct txx9spi *c, int reg) -{ - return __raw_readl(c->membase + reg); -} -static void txx9spi_wr(struct txx9spi *c, u32 val, int reg) -{ - __raw_writel(val, c->membase + reg); -} - -static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c, - int on, unsigned int cs_delay) -{ - /* - * The GPIO descriptor will track polarity inversion inside - * gpiolib. - */ - if (on) { - /* deselect the chip with cs_change hint in last transfer */ - if (c->last_chipselect) - gpiod_set_value(c->last_chipselect, - !c->last_chipselect_val); - c->last_chipselect = spi->cs_gpiod; - c->last_chipselect_val = on; - } else { - c->last_chipselect = NULL; - ndelay(cs_delay); /* CS Hold Time */ - } - gpiod_set_value(spi->cs_gpiod, on); - ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */ -} - -static int txx9spi_setup(struct spi_device *spi) -{ - struct txx9spi *c = spi_master_get_devdata(spi->master); - - if (!spi->max_speed_hz) - return -EINVAL; - - /* deselect chip */ - spin_lock(&c->lock); - txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz); - spin_unlock(&c->lock); - - return 0; -} - -static irqreturn_t txx9spi_interrupt(int irq, void *dev_id) -{ - struct txx9spi *c = dev_id; - - /* disable rx intr */ - txx9spi_wr(c, txx9spi_rd(c, TXx9_SPCR0) & ~TXx9_SPCR0_RBSIE, - TXx9_SPCR0); - wake_up(&c->waitq); - return IRQ_HANDLED; -} - -static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m) -{ - struct spi_device *spi = m->spi; - struct spi_transfer *t; - unsigned int cs_delay; - unsigned int cs_change = 1; - int status = 0; - u32 mcr; - u32 prev_speed_hz = 0; - u8 prev_bits_per_word = 0; - - /* CS setup/hold/recovery time in nsec */ - cs_delay = 100 + (NSEC_PER_SEC / 2) / spi->max_speed_hz; - - mcr = txx9spi_rd(c, TXx9_SPMCR); - if (unlikely((mcr & TXx9_SPMCR_OPMODE) == TXx9_SPMCR_ACTIVE)) { - dev_err(&spi->dev, "Bad mode.\n"); - status = -EIO; - goto exit; - } - mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR); - - /* enter config mode */ - txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR); - txx9spi_wr(c, TXx9_SPCR0_SBOS - | ((spi->mode & SPI_CPOL) ? TXx9_SPCR0_SPOL : 0) - | ((spi->mode & SPI_CPHA) ? TXx9_SPCR0_SPHA : 0) - | 0x08, - TXx9_SPCR0); - - list_for_each_entry(t, &m->transfers, transfer_list) { - const void *txbuf = t->tx_buf; - void *rxbuf = t->rx_buf; - u32 data; - unsigned int len = t->len; - unsigned int wsize; - u32 speed_hz = t->speed_hz; - u8 bits_per_word = t->bits_per_word; - - wsize = bits_per_word >> 3; /* in bytes */ - - if (prev_speed_hz != speed_hz - || prev_bits_per_word != bits_per_word) { - int n = DIV_ROUND_UP(c->baseclk, speed_hz) - 1; - - n = clamp(n, SPI_MIN_DIVIDER, SPI_MAX_DIVIDER); - /* enter config mode */ - txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, - TXx9_SPMCR); - txx9spi_wr(c, (n << 8) | bits_per_word, TXx9_SPCR1); - /* enter active mode */ - txx9spi_wr(c, mcr | TXx9_SPMCR_ACTIVE, TXx9_SPMCR); - - prev_speed_hz = speed_hz; - prev_bits_per_word = bits_per_word; - } - - if (cs_change) - txx9spi_cs_func(spi, c, 1, cs_delay); - cs_change = t->cs_change; - while (len) { - unsigned int count = SPI_FIFO_SIZE; - int i; - u32 cr0; - - if (len < count * wsize) - count = len / wsize; - /* now tx must be idle... */ - while (!(txx9spi_rd(c, TXx9_SPSR) & TXx9_SPSR_SIDLE)) - cpu_relax(); - cr0 = txx9spi_rd(c, TXx9_SPCR0); - cr0 &= ~TXx9_SPCR0_RXIFL_MASK; - cr0 |= (count - 1) << 12; - /* enable rx intr */ - cr0 |= TXx9_SPCR0_RBSIE; - txx9spi_wr(c, cr0, TXx9_SPCR0); - /* send */ - for (i = 0; i < count; i++) { - if (txbuf) { - data = (wsize == 1) - ? *(const u8 *)txbuf - : *(const u16 *)txbuf; - txx9spi_wr(c, data, TXx9_SPDR); - txbuf += wsize; - } else - txx9spi_wr(c, 0, TXx9_SPDR); - } - /* wait all rx data */ - wait_event(c->waitq, - txx9spi_rd(c, TXx9_SPSR) & TXx9_SPSR_RBSI); - /* receive */ - for (i = 0; i < count; i++) { - data = txx9spi_rd(c, TXx9_SPDR); - if (rxbuf) { - if (wsize == 1) - *(u8 *)rxbuf = data; - else - *(u16 *)rxbuf = data; - rxbuf += wsize; - } - } - len -= count * wsize; - } - m->actual_length += t->len; - spi_transfer_delay_exec(t); - - if (!cs_change) - continue; - if (t->transfer_list.next == &m->transfers) - break; - /* sometimes a short mid-message deselect of the chip - * may be needed to terminate a mode or command - */ - txx9spi_cs_func(spi, c, 0, cs_delay); - } - -exit: - m->status = status; - if (m->complete) - m->complete(m->context); - - /* normally deactivate chipselect ... unless no error and - * cs_change has hinted that the next message will probably - * be for this chip too. - */ - if (!(status == 0 && cs_change)) - txx9spi_cs_func(spi, c, 0, cs_delay); - - /* enter config mode */ - txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR); -} - -static void txx9spi_work(struct work_struct *work) -{ - struct txx9spi *c = container_of(work, struct txx9spi, work); - unsigned long flags; - - spin_lock_irqsave(&c->lock, flags); - while (!list_empty(&c->queue)) { - struct spi_message *m; - - m = container_of(c->queue.next, struct spi_message, queue); - list_del_init(&m->queue); - spin_unlock_irqrestore(&c->lock, flags); - - txx9spi_work_one(c, m); - - spin_lock_irqsave(&c->lock, flags); - } - spin_unlock_irqrestore(&c->lock, flags); -} - -static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) -{ - struct spi_master *master = spi->master; - struct txx9spi *c = spi_master_get_devdata(master); - struct spi_transfer *t; - unsigned long flags; - - m->actual_length = 0; - - /* check each transfer's parameters */ - list_for_each_entry(t, &m->transfers, transfer_list) { - if (!t->tx_buf && !t->rx_buf && t->len) - return -EINVAL; - } - - spin_lock_irqsave(&c->lock, flags); - list_add_tail(&m->queue, &c->queue); - schedule_work(&c->work); - spin_unlock_irqrestore(&c->lock, flags); - - return 0; -} - -/* - * Chip select uses GPIO only, further the driver is using the chip select - * numer (from the device tree "reg" property, and this can only come from - * device tree since this i MIPS and there is no way to pass platform data) as - * the GPIO number. As the platform has only one GPIO controller (the txx9 GPIO - * chip) it is thus using the chip select number as an offset into that chip. - * This chip has a maximum of 16 GPIOs 0..15 and this is what all platforms - * register. - * - * We modernized this behaviour by explicitly converting that offset to an - * offset on the GPIO chip using a GPIO descriptor machine table of the same - * size as the txx9 GPIO chip with a 1-to-1 mapping of chip select to GPIO - * offset. - * - * This is admittedly a hack, but it is countering the hack of using "reg" to - * contain a GPIO offset when it should be using "cs-gpios" as the SPI bindings - * state. - */ -static struct gpiod_lookup_table txx9spi_cs_gpio_table = { - .dev_id = "spi0", - .table = { - GPIO_LOOKUP_IDX("TXx9", 0, "cs", 0, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 1, "cs", 1, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 2, "cs", 2, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 3, "cs", 3, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 4, "cs", 4, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 5, "cs", 5, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 6, "cs", 6, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 7, "cs", 7, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 8, "cs", 8, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 9, "cs", 9, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 10, "cs", 10, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 11, "cs", 11, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 12, "cs", 12, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 13, "cs", 13, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 14, "cs", 14, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX("TXx9", 15, "cs", 15, GPIO_ACTIVE_LOW), - { }, - }, -}; - -static int txx9spi_probe(struct platform_device *dev) -{ - struct spi_master *master; - struct txx9spi *c; - struct resource *res; - int ret = -ENODEV; - u32 mcr; - int irq; - - master = spi_alloc_master(&dev->dev, sizeof(*c)); - if (!master) - return ret; - c = spi_master_get_devdata(master); - platform_set_drvdata(dev, master); - - INIT_WORK(&c->work, txx9spi_work); - spin_lock_init(&c->lock); - INIT_LIST_HEAD(&c->queue); - init_waitqueue_head(&c->waitq); - - c->clk = devm_clk_get(&dev->dev, "spi-baseclk"); - if (IS_ERR(c->clk)) { - ret = PTR_ERR(c->clk); - c->clk = NULL; - goto exit; - } - ret = clk_prepare_enable(c->clk); - if (ret) { - c->clk = NULL; - goto exit; - } - c->baseclk = clk_get_rate(c->clk); - master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); - master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - c->membase = devm_ioremap_resource(&dev->dev, res); - if (IS_ERR(c->membase)) - goto exit_busy; - - /* enter config mode */ - mcr = txx9spi_rd(c, TXx9_SPMCR); - mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR); - txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR); - - irq = platform_get_irq(dev, 0); - if (irq < 0) - goto exit_busy; - ret = devm_request_irq(&dev->dev, irq, txx9spi_interrupt, 0, - "spi_txx9", c); - if (ret) - goto exit; - - c->last_chipselect = NULL; - - dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n", - (unsigned long long)res->start, irq, - (c->baseclk + 500000) / 1000000); - - gpiod_add_lookup_table(&txx9spi_cs_gpio_table); - - /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; - - master->bus_num = dev->id; - master->setup = txx9spi_setup; - master->transfer = txx9spi_transfer; - master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */ - master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - master->use_gpio_descriptors = true; - - ret = devm_spi_register_master(&dev->dev, master); - if (ret) - goto exit; - return 0; -exit_busy: - ret = -EBUSY; -exit: - clk_disable_unprepare(c->clk); - spi_master_put(master); - return ret; -} - -static int txx9spi_remove(struct platform_device *dev) -{ - struct spi_master *master = platform_get_drvdata(dev); - struct txx9spi *c = spi_master_get_devdata(master); - - flush_work(&c->work); - clk_disable_unprepare(c->clk); - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:spi_txx9"); - -static struct platform_driver txx9spi_driver = { - .probe = txx9spi_probe, - .remove = txx9spi_remove, - .driver = { - .name = "spi_txx9", - }, -}; - -static int __init txx9spi_init(void) -{ - return platform_driver_register(&txx9spi_driver); -} -subsys_initcall(txx9spi_init); - -static void __exit txx9spi_exit(void) -{ - platform_driver_unregister(&txx9spi_driver); -} -module_exit(txx9spi_exit); - -MODULE_DESCRIPTION("TXx9 SPI Driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3a5c09c8d1ed9a7323f0e5c435021531f0865c16 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Wed, 23 Dec 2020 00:14:19 +0530 Subject: spi: cadence-quadspi: Set master max_speed_hz As of commit 9326e4f1e5dd ("spi: Limit the spi device max speed to controller's max speed"), the SPI device max speed is set to the controller's max speed if it is larger. The Cadence QSPI controller does not set the controller's max speed so it is left at its initial value of 0. This means the SPI device max speed is always set to 0. The SPI device max speed is used to calculate the baud rate divider when performing an operation. If this speed is 0, the default divider of 32 is used. No matter what speed is specified by the device tree property 'spi-max-frequency', the device will always operate at ref_clk / 32. Fix this by setting master->max_speed_hz to the ref clock speed so the correct divider can be calculated. Signed-off-by: Pratyush Yadav Link: https://lore.kernel.org/r/20201222184425.7028-2-p.yadav@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index ba7d40c2922f..ea3890c7d9ff 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1279,6 +1279,7 @@ static int cqspi_probe(struct platform_device *pdev) reset_control_deassert(rstc_ocp); cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); + master->max_speed_hz = cqspi->master_ref_clk_hz; ddata = of_device_get_match_data(dev); if