diff options
author | Mark Brown <broonie@kernel.org> | 2020-07-29 15:52:00 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-07-29 15:52:00 +0200 |
commit | 11ba28229f8258164731e42f4c3e93762cb6578e (patch) | |
tree | fe4f9a734dcae7507697a0dbec48fc064d2a31d0 /drivers/spi | |
parent | Merge remote-tracking branch 'spi/for-5.8' into spi-linus (diff) | |
parent | Merge series "Some bug fix for lpspi" from Clark Wang <xiaoning.wang@nxp.com>: (diff) | |
download | linux-11ba28229f8258164731e42f4c3e93762cb6578e.tar.xz linux-11ba28229f8258164731e42f4c3e93762cb6578e.zip |
Merge remote-tracking branch 'spi/for-5.9' into spi-next
Diffstat (limited to 'drivers/spi')
53 files changed, 2532 insertions, 758 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8f1f8fca79e3..c3008e423f59 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -59,6 +59,7 @@ comment "SPI Master Controller Drivers" config SPI_ALTERA tristate "Altera SPI Controller" + select REGMAP_MMIO help This is the driver for the Altera SPI Controller. @@ -102,7 +103,7 @@ config SPI_AT91_USART config SPI_ATMEL_QUADSPI tristate "Atmel Quad SPI Controller" - depends on ARCH_AT91 || (ARM && COMPILE_TEST && !ARCH_EBSA110) + depends on ARCH_AT91 || COMPILE_TEST depends on OF && HAS_IOMEM help This enables support for the Quad SPI controller in master mode. @@ -149,13 +150,13 @@ config SPI_BCM2835AUX config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" - depends on BCM63XX || COMPILE_TEST + depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST help Enable support for the SPI controller on the Broadcom BCM63xx SoCs. config SPI_BCM63XX_HSSPI tristate "Broadcom BCM63XX HS SPI controller driver" - depends on BCM63XX || ARCH_BCM_63XX || COMPILE_TEST + depends on BCM63XX || BMIPS_GENERIC || ARCH_BCM_63XX || COMPILE_TEST help This enables support for the High Speed SPI controller present on newer Broadcom BCM63XX SoCs. @@ -168,7 +169,7 @@ config SPI_BCM_QSPI help Enables support for the Broadcom SPI flash and MSPI controller. Select this option for any one of BRCMSTB, iProc NSP and NS2 SoCs - based platforms. This driver works for both SPI master for spi-nor + based platforms. This driver works for both SPI master for SPI NOR flash device as well as MSPI device. config SPI_BITBANG @@ -200,6 +201,17 @@ config SPI_CADENCE This selects the Cadence SPI controller master driver used by Xilinx Zynq and ZynqMP. +config SPI_CADENCE_QUADSPI + tristate "Cadence Quad SPI controller" + depends on OF && (ARM || ARM64 || COMPILE_TEST) + help + Enable support for the Cadence Quad SPI Flash controller. + + Cadence QSPI is a specialized controller for connecting an SPI + Flash over 1/2/4-bit wide bus. Enable this option if you have a + device with a Cadence QSPI controller and want to access the + Flash as an MTD device. + config SPI_CLPS711X tristate "CLPS711X host SPI controller" depends on ARCH_CLPS711X || COMPILE_TEST @@ -299,11 +311,11 @@ config SPI_FSL_QUADSPI supports the high-level SPI memory interface. config SPI_HISI_SFC_V3XX - tristate "HiSilicon SPI-NOR Flash Controller for Hi16XX chipsets" + tristate "HiSilicon SPI NOR Flash Controller for Hi16XX chipsets" depends on (ARM64 && ACPI) || COMPILE_TEST depends on HAS_IOMEM help - This enables support for HiSilicon v3xx SPI-NOR flash controller + This enables support for HiSilicon v3xx SPI NOR flash controller found in hi16xx chipsets. config SPI_NXP_FLEXSPI @@ -465,9 +477,9 @@ config SPI_MTK_NOR depends on ARCH_MEDIATEK || COMPILE_TEST help This enables support for SPI NOR controller found on MediaTek - ARM SoCs. This is a controller specifically for SPI-NOR flash. + ARM SoCs. This is a controller specifically for SPI NOR flash. It can perform generic SPI transfers up to 6 bytes via generic - SPI interface as well as several SPI-NOR specific instructions + SPI interface as well as several SPI NOR specific instructions via SPI MEM interface. config SPI_NPCM_FIU @@ -489,11 +501,11 @@ config SPI_NPCM_PSPI config SPI_LANTIQ_SSC tristate "Lantiq SSC SPI controller" - depends on LANTIQ || COMPILE_TEST + depends on LANTIQ || X86 || COMPILE_TEST help This driver supports the Lantiq SSC SPI controller in master mode. This controller is found on Intel (former Lantiq) SoCs like - the Danube, Falcon, xRX200, xRX300. + the Danube, Falcon, xRX200, xRX300, Lightning Mountain. config SPI_OC_TINY tristate "OpenCores tiny SPI" @@ -605,6 +617,12 @@ config SPI_RB4XX help SPI controller driver for the Mikrotik RB4xx series boards. +config SPI_RPCIF + tristate "Renesas RPC-IF SPI driver" + depends on RENESAS_RPCIF + help + SPI driver for Renesas R-Car Gen3 RPC-IF. + config SPI_RSPI tristate "Renesas RSPI/QSPI controller" depends on SUPERH || ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index d2e41d3d464a..cf955ea803cd 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi. obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o +obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o @@ -92,6 +93,7 @@ obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o +obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index cb44d1e169aa..8c009c175f2c 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -285,6 +285,12 @@ static bool atmel_qspi_supports_op(struct spi_mem *mem, op->dummy.nbytes == 0) return false; + /* DTR ops not supported. */ + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + return false; + if (op->cmd.nbytes != 1) + return false; + return true; } @@ -424,11 +430,11 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) /* Send/Receive data */ if (op->data.dir == SPI_MEM_DATA_IN) - _memcpy_fromio(op->data.buf.in, aq->mem + offset, - op->data.nbytes); + memcpy_fromio(op->data.buf.in, aq->mem + offset, + op->data.nbytes); else - _memcpy_toio(aq->mem + offset, op->data.buf.out, - op->data.nbytes); + memcpy_toio(aq->mem + offset, op->data.buf.out, + op->data.nbytes); /* Release the chip-select */ atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR); diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 41d71ba7fd32..809bfff3690a 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -14,6 +14,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/spi/altera.h> #include <linux/spi/spi.h> #include <linux/io.h> #include <linux/of.h> @@ -40,19 +41,61 @@ #define ALTERA_SPI_CONTROL_IE_MSK 0x100 #define ALTERA_SPI_CONTROL_SSO_MSK 0x400 +#define ALTERA_SPI_MAX_CS 32 + +enum altera_spi_type { + ALTERA_SPI_TYPE_UNKNOWN, + ALTERA_SPI_TYPE_SUBDEV, +}; + struct altera_spi { - void __iomem *base; int irq; int len; int count; int bytes_per_word; - unsigned long imr; + u32 imr; /* data buffers */ const unsigned char *tx; unsigned char *rx; + + struct regmap *regmap; + u32 regoff; + struct device *dev; +}; + +static const struct regmap_config spi_altera_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, }; +static int altr_spi_writel(struct altera_spi *hw, unsigned int reg, + unsigned int val) +{ + int ret; + + ret = regmap_write(hw->regmap, hw->regoff + reg, val); + if (ret) + dev_err(hw->dev, "fail to write reg 0x%x val 0x%x: %d\n", + reg, val, ret); + + return ret; +} + +static int altr_spi_readl(struct altera_spi *hw, unsigned int reg, + unsigned int *val) +{ + int ret; + + ret = regmap_read(hw->regmap, hw->regoff + reg, val); + if (ret) + dev_err(hw->dev, "fail to read reg 0x%x: %d\n", reg, ret); + + return ret; +} + static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev) { return spi_master_get_devdata(sdev->master); @@ -64,12 +107,13 @@ static void altera_spi_set_cs(struct spi_device *spi, bool is_high) if (is_high) { hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); - writel(0, hw->base + ALTERA_SPI_SLAVE_SEL); + altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); + altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 0); } else { - writel(BIT(spi->chip_select), hw->base + ALTERA_SPI_SLAVE_SEL); + altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, + BIT(spi->chip_select)); hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); + altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); } } @@ -86,17 +130,24 @@ static void altera_spi_tx_word(struct altera_spi *hw) txd = (hw->tx[hw->count * 2] | (hw->tx[hw->count * 2 + 1] << 8)); break; + case 4: + txd = (hw->tx[hw->count * 4] + | (hw->tx[hw->count * 4 + 1] << 8) + | (hw->tx[hw->count * 4 + 2] << 16) + | (hw->tx[hw->count * 4 + 3] << 24)); + break; + } } - writel(txd, hw->base + ALTERA_SPI_TXDATA); + altr_spi_writel(hw, ALTERA_SPI_TXDATA, txd); } static void altera_spi_rx_word(struct altera_spi *hw) { unsigned int rxd; - rxd = readl(hw->base + ALTERA_SPI_RXDATA); + altr_spi_readl(hw, ALTERA_SPI_RXDATA, &rxd); if (hw->rx) { switch (hw->bytes_per_word) { case 1: @@ -106,6 +157,13 @@ static void altera_spi_rx_word(struct altera_spi *hw) hw->rx[hw->count * 2] = rxd; hw->rx[hw->count * 2 + 1] = rxd >> 8; break; + case 4: + hw->rx[hw->count * 4] = rxd; + hw->rx[hw->count * 4 + 1] = rxd >> 8; + hw->rx[hw->count * 4 + 2] = rxd >> 16; + hw->rx[hw->count * 4 + 3] = rxd >> 24; + break; + } } @@ -116,6 +174,7 @@ static int altera_spi_txrx(struct spi_master *master, struct spi_device *spi, struct spi_transfer *t) { struct altera_spi *hw = spi_master_get_devdata(master); + u32 val; hw->tx = t->tx_buf; hw->rx = t->rx_buf; @@ -126,7 +185,7 @@ static int altera_spi_txrx(struct spi_master *master, if (hw->irq >= 0) { /* enable receive interrupt */ hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); + altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); /* send the first byte */ altera_spi_tx_word(hw); @@ -134,9 +193,13 @@ static int altera_spi_txrx(struct spi_master *master, while (hw->count < hw->len) { altera_spi_tx_word(hw); - while (!(readl(hw->base + ALTERA_SPI_STATUS) & - ALTERA_SPI_STATUS_RRDY_MSK)) + for (;;) { + altr_spi_readl(hw, ALTERA_SPI_STATUS, &val); + if (val & ALTERA_SPI_STATUS_RRDY_MSK) + break; + cpu_relax(); + } altera_spi_rx_word(hw); } @@ -158,7 +221,7 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) } else { /* disable receive interrupt */ hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); + altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); spi_finalize_current_transfer(master); } @@ -168,9 +231,14 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) static int altera_spi_probe(struct platform_device *pdev) { + const struct platform_device_id *platid = platform_get_device_id(pdev); + struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev); + enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN; struct altera_spi *hw; struct spi_master *master; int err = -ENODEV; + u32 val; + u16 i; master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi)); if (!master) @@ -178,27 +246,72 @@ static int altera_spi_probe(struct platform_device *pdev) /* setup the master state. */ master->bus_num = pdev->id; - master->num_chipselect = 16; - master->mode_bits = SPI_CS_HIGH; - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + + if (pdata) { + if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) { + dev_err(&pdev->dev, + "Invalid number of chipselect: %hu\n", + pdata->num_chipselect); + return -EINVAL; + } + + master->num_chipselect = pdata->num_chipselect; + master->mode_bits = pdata->mode_bits; + master->bits_per_word_mask = pdata->bits_per_word_mask; + } else { + master->num_chipselect = 16; + master->mode_bits = SPI_CS_HIGH; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + } + master->dev.of_node = pdev->dev.of_node; master->transfer_one = altera_spi_txrx; master->set_cs = altera_spi_set_cs; hw = spi_master_get_devdata(master); + hw->dev = &pdev->dev; + + if (platid) + type = platid->driver_data; /* find and map our resources */ - hw->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hw->base)) { - err = PTR_ERR(hw->base); - goto exit; + if (type == ALTERA_SPI_TYPE_SUBDEV) { + struct resource *regoff; + + hw->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!hw->regmap) { + dev_err(&pdev->dev, "get regmap failed\n"); + goto exit; + } + + regoff = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (regoff) + hw->regoff = regoff->start; + } else { + void __iomem *res; + + res = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(res)) { + err = PTR_ERR(res); + goto exit; + } + + hw->regmap = devm_regmap_init_mmio(&pdev->dev, res, + &spi_altera_config); + if (IS_ERR(hw->regmap)) { + dev_err(&pdev->dev, "regmap mmio init failed\n"); + err = PTR_ERR(hw->regmap); + goto exit; + } } + /* program defaults into the registers */ hw->imr = 0; /* disable spi interrupts */ - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); - writel(0, hw->base + ALTERA_SPI_STATUS); /* clear status reg */ - if (readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK) - readl(hw->base + ALTERA_SPI_RXDATA); /* flush rxdata */ + altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); + altr_spi_writel(hw, ALTERA_SPI_STATUS, 0); /* clear status reg */ + altr_spi_readl(hw, ALTERA_SPI_STATUS, &val); + if (val & ALTERA_SPI_STATUS_RRDY_MSK) + altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */ /* irq is optional */ hw->irq = platform_get_irq(pdev, 0); if (hw->irq >= 0) { @@ -211,7 +324,17 @@ static int altera_spi_probe(struct platform_device *pdev) err = devm_spi_register_master(&pdev->dev, master); if (err) goto exit; - dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq); + + if (pdata) { + for (i = 0; i < pdata->num_devices; i++) { + if (!spi_new_device(master, pdata->devices + i)) + dev_warn(&pdev->dev, + "unable to create SPI device: %s\n", + pdata->devices[i].modalias); + } + } + + dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq); return 0; exit: @@ -228,6 +351,13 @@ static const struct of_device_id altera_spi_match[] = { MODULE_DEVICE_TABLE(of, altera_spi_match); #endif /* CONFIG_OF */ +static const struct platform_device_id altera_spi_ids[] = { + { DRV_NAME, ALTERA_SPI_TYPE_UNKNOWN }, + { "subdev_spi_altera", ALTERA_SPI_TYPE_SUBDEV }, + { } +}; +MODULE_DEVICE_TABLE(platform, altera_spi_ids); + static struct platform_driver altera_spi_driver = { .probe = altera_spi_probe, .driver = { @@ -235,6 +365,7 @@ static struct platform_driver altera_spi_driver = { .pm = NULL, .of_match_table = of_match_ptr(altera_spi_match), }, + .id_table = altera_spi_ids, }; module_platform_driver(altera_spi_driver); diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index d0aacd4de1b9..7f629544060d 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -294,11 +294,13 @@ err_free_master: return err; } +#ifdef CONFIG_ACPI static const struct acpi_device_id spi_acpi_match[] = { { "AMDI0061", 0 }, {}, }; MODULE_DEVICE_TABLE(acpi, spi_acpi_match); +#endif static struct platform_driver amd_spi_driver = { .driver = { diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index 88033422a42a..8c8352625d23 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -681,13 +681,6 @@ static const struct dev_pm_ops at91_usart_spi_pm_ops = { at91_usart_spi_runtime_resume, NULL) }; -static const struct of_device_id at91_usart_spi_dt_ids[] = { - { .compatible = "microchip,at91sam9g45-usart-spi"}, - { /* sentinel */} -}; - -MODULE_DEVICE_TABLE(of, at91_usart_spi_dt_ids); - static struct platform_driver at91_usart_spi_driver = { .driver = { .name = "at91_usart_spi", diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 57ee8c3b7972..2cfe6253a784 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1546,10 +1546,9 @@ static int atmel_spi_probe(struct platform_device *pdev) return PTR_ERR(clk); /* setup spi core then atmel-specific driver state */ - ret = -ENOMEM; master = spi_alloc_master(&pdev->dev, sizeof(*as)); if (!master) - goto out_free; + return -ENOMEM; /* the spi->mode bits understood by this driver: */ master->use_gpio_descriptors = true; @@ -1678,7 +1677,6 @@ out_free_dma: clk_disable_unprepare(clk); out_free_irq: out_unmap_regs: -out_free: spi_master_put(master); return ret; } diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 237bd306c268..c45d76c848c8 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -86,6 +86,7 @@ MODULE_PARM_DESC(polling_limit_us, * @clk: core clock, divided to calculate serial clock * @irq: interrupt, signals TX FIFO empty or RX FIFO ¾ full * @tfr: SPI transfer currently processed + * @ctlr: SPI controller reverse lookup * @tx_buf: pointer whence next transmitted byte is read * @rx_buf: pointer where next received byte is written * @tx_len: remaining bytes to transmit @@ -125,6 +126,7 @@ struct bcm2835_spi { struct clk *clk; int irq; struct spi_transfer *tfr; + struct spi_controller *ctlr; const u8 *tx_buf; u8 *rx_buf; int tx_len; @@ -243,13 +245,13 @@ static inline void bcm2835_rd_fifo_count(struct bcm2835_spi *bs, int count) bs->rx_len -= count; - while (count > 0) { + do { val = bcm2835_rd(bs, BCM2835_SPI_FIFO); len = min(count, 4); memcpy(bs->rx_buf, &val, len); bs->rx_buf += len; count -= 4; - } + } while (count > 0); } /** @@ -269,7 +271,7 @@ static inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count) bs->tx_len -= count; - while (count > 0) { + do { if (bs->tx_buf) { len = min(count, 4); memcpy(&val, bs->tx_buf, len); @@ -279,7 +281,7 @@ static inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count) } bcm2835_wr(bs, BCM2835_SPI_FIFO, val); count -= 4; - } + } while (count > 0); } /** @@ -308,12 +310,11 @@ static inline void bcm2835_rd_fifo_blind(struct bcm2835_spi *bs, int count) count = min(count, bs->rx_len); bs->rx_len -= count; - while (count) { + do { val = bcm2835_rd(bs, BCM2835_SPI_FIFO); if (bs->rx_buf) *bs->rx_buf++ = val; - count--; - } + } while (--count); } /** @@ -328,16 +329,14 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count) count = min(count, bs->tx_len); bs->tx_len -= count; - while (count) { + do { val = bs->tx_buf ? *bs->tx_buf++ : 0; bcm2835_wr(bs, BCM2835_SPI_FIFO, val); - count--; - } + } while (--count); } -static void bcm2835_spi_reset_hw(struct spi_controller *ctlr) +static void bcm2835_spi_reset_hw(struct bcm2835_spi *bs) { - struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* Disable SPI interrupts and transfer */ @@ -363,8 +362,7 @@ static void bcm2835_spi_reset_hw(struct spi_controller *ctlr) static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) { - struct spi_controller *ctlr = dev_id; - struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + struct bcm2835_spi *bs = dev_id; u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* @@ -386,9 +384,9 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) if (!bs->rx_len) { /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(ctlr); + bcm2835_spi_reset_hw(bs); /* wake up the framework */ - complete(&ctlr->xfer_completion); + complete(&bs->ctlr->xfer_completion); } return IRQ_HANDLED; @@ -607,7 +605,7 @@ static void bcm2835_spi_dma_rx_done(void *data) bcm2835_spi_undo_prologue(bs); /* reset fifo and HW */ - bcm2835_spi_reset_hw(ctlr); + bcm2835_spi_reset_hw(bs); /* and mark as completed */; complete(&ctlr->xfer_completion); @@ -641,7 +639,7 @@ static void bcm2835_spi_dma_tx_done(void *data) dmaengine_terminate_async(ctlr->dma_rx); bcm2835_spi_undo_prologue(bs); - bcm2835_spi_reset_hw(ctlr); + bcm2835_spi_reset_hw(bs); complete(&ctlr->xfer_completion); } @@ -825,14 +823,14 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, if (!bs->rx_buf && !bs->tx_dma_active && cmpxchg(&bs->rx_dma_active, true, false)) { dmaengine_terminate_async(ctlr->dma_rx); - bcm2835_spi_reset_hw(ctlr); + bcm2835_spi_reset_hw(bs); } /* wait for wakeup in framework */ return 1; err_reset_hw: - bcm2835_spi_reset_hw(ctlr); + bcm2835_spi_reset_hw(bs); bcm2835_spi_undo_prologue(bs); return ret; } @@ -1074,7 +1072,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr, } /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(ctlr); + bcm2835_spi_reset_hw(bs); /* and return without waiting for completion */ return 0; } @@ -1084,7 +1082,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, struct spi_transfer *tfr) { struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); - unsigned long spi_hz, clk_hz, cdiv, spi_used_hz; + unsigned long spi_hz, clk_hz, cdiv; unsigned long hz_per_byte, byte_limit; u32 cs = bs->prepare_cs[spi->chip_select]; @@ -1104,7 +1102,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, } else { cdiv = 0; /* 0 is the slowest we can go */ } - spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536); + tfr->effective_speed_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536); bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); /* handle all the 3-wire mode */ @@ -1124,7 +1122,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, * per 300,000 Hz of bus clock. */ hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0; - byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1; + byte_limit = hz_per_byte ? tfr->effective_speed_hz / hz_per_byte : 1; /* run in polling mode for short transfers */ if (tfr->len < byte_limit) @@ -1182,7 +1180,7 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr, bcm2835_spi_undo_prologue(bs); /* and reset */ - bcm2835_spi_reset_hw(ctlr); + bcm2835_spi_reset_hw(bs); } static int chip_match_name(struct gpio_chip *chip, void *data) @@ -1311,6 +1309,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) ctlr->dev.of_node = pdev->dev.of_node; bs = spi_controller_get_devdata(ctlr); + bs->ctlr = ctlr; bs->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(bs->regs)) { @@ -1345,7 +1344,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, - dev_name(&pdev->dev), ctlr); + dev_name(&pdev->dev), bs); if (err) { dev_err(&pdev->dev, "could not request IRQ: %d\n", err); goto out_dma_release; diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index c331efd6e86b..2f717812c766 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -345,7 +345,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, struct spi_transfer *tfr) { struct bcm2835aux_spi *bs = spi_master_get_devdata(master); - unsigned long spi_hz, clk_hz, speed, spi_used_hz; + unsigned long spi_hz, clk_hz, speed; unsigned long hz_per_byte, byte_limit; /* calculate the registers to handle @@ -374,7 +374,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, /* set the new speed */ bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT; - spi_used_hz = clk_hz / (2 * (speed + 1)); + tfr->effective_speed_hz = clk_hz / (2 * (speed + 1)); /* set transmit buffers and length */ bs->tx_buf = tfr->tx_buf; @@ -391,7 +391,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, * 30 µs per 300,000 Hz of bus clock. */ hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0; - byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1; + byte_limit = hz_per_byte ? tfr->effective_speed_hz / hz_per_byte : 1; /* run in polling mode for short transfers */ if (tfr->len < byte_limit) diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 6c235306c0e4..9909b18f3c5a 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -20,6 +20,7 @@ #include <linux/spi/spi.h> #include <linux/mutex.h> #include <linux/of.h> +#include <linux/reset.h> #define HSSPI_GLOBAL_CTRL_REG 0x0 #define GLOBAL_CTRL_CS_POLARITY_SHIFT 0 @@ -334,6 +335,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) struct clk *clk, *pll_clk = NULL; int irq, ret; u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS; + struct reset_control *reset; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -348,10 +350,20 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); + reset = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(reset)) + return PTR_ERR(reset); + ret = clk_prepare_enable(clk); if (ret) return ret; + ret = reset_control_reset(reset); + if (ret) { + dev_err(dev, "unable to reset device: %d\n", ret); + goto out_disable_clk; + } + rate = clk_get_rate(clk); if (!rate) { pll_clk = devm_clk_get(dev, "pll"); diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 0f1b10a4ef0c..96d075e633f4 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -18,6 +18,7 @@ #include <linux/err.h> #include <linux/pm_runtime.h> #include <linux/of.h> +#include <linux/reset.h> /* BCM 6338/6348 SPI core */ #define SPI_6348_RSET_SIZE 64 @@ -493,6 +494,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) struct bcm63xx_spi *bs; int ret; u32 num_cs = BCM63XX_SPI_MAX_CS; + struct reset_control *reset; if (dev->of_node) { const struct of_device_id *match; @@ -529,6 +531,10 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) return PTR_ERR(clk); } + reset = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(reset)) + return PTR_ERR(reset); + master = spi_alloc_master(dev, sizeof(*bs)); if (!master) { dev_err(dev, "out of memory\n"); @@ -579,6 +585,12 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) if (ret) goto out_err; + ret = reset_control_reset(reset); + if (ret) { + dev_err(dev, "unable to reset device: %d\n", ret); + goto out_clk_disable; + } + bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); /* register and we are done */ diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 68491a8bf7b5..1a7352abd878 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -174,7 +174,7 @@ int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t) } EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer); -/** +/* * spi_bitbang_setup - default setup for per-word I/O loops */ int spi_bitbang_setup(struct spi_device *spi) @@ -208,7 +208,7 @@ int spi_bitbang_setup(struct spi_device *spi) } EXPORT_SYMBOL_GPL(spi_bitbang_setup); -/** +/* * spi_bitbang_cleanup - default cleanup for per-word I/O loops */ void spi_bitbang_cleanup(struct spi_device *spi) @@ -427,7 +427,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) } EXPORT_SYMBOL_GPL(spi_bitbang_start); -/** +/* * spi_bitbang_stop - stops the task providing spi communication */ void spi_bitbang_stop(struct spi_bitbang *bitbang) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c new file mode 100644 index 000000000000..1c1a9d17eec0 --- /dev/null +++ b/drivers/spi/spi-cadence-quadspi.c @@ -0,0 +1,1419 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Driver for Cadence QSPI Controller +// +// Copyright Altera Corporation (C) 2012-2014. All rights reserved. +// Copyright Intel Corporation (C) 2019-2020. All rights reserved. +// Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com + +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/sched.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> +#include <linux/timer.h> + +#define CQSPI_NAME "cadence-qspi" +#define CQSPI_MAX_CHIPSELECT 16 + +/* Quirks */ +#define CQSPI_NEEDS_WR_DELAY BIT(0) +#define CQSPI_DISABLE_DAC_MODE BIT(1) + +/* Capabilities */ +#define CQSPI_SUPPORTS_OCTAL BIT(0) + +struct cqspi_st; + +struct cqspi_flash_pdata { + struct cqspi_st *cqspi; + u32 clk_rate; + u32 read_delay; + u32 tshsl_ns; + u32 tsd2d_ns; + u32 tchsh_ns; + u32 tslch_ns; + u8 inst_width; + u8 addr_width; + u8 data_width; + u8 cs; +}; + +struct cqspi_st { + struct platform_device *pdev; + + struct clk *clk; + unsigned int sclk; + + void __iomem *iobase; + void __iomem *ahb_base; + resource_size_t ahb_size; + struct completion transfer_complete; + + struct dma_chan *rx_chan; + struct completion rx_dma_complete; + dma_addr_t mmap_phys_base; + + int current_cs; + unsigned long master_ref_clk_hz; + bool is_decoded_cs; + u32 fifo_depth; + u32 fifo_width; + bool rclk_en; + u32 trigger_address; + u32 wr_delay; + bool use_direct_mode; + struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT]; +}; + +struct cqspi_driver_platdata { + u32 hwcaps_mask; + u8 quirks; +}; + +/* Operation timeout value */ +#define CQSPI_TIMEOUT_MS 500 +#define CQSPI_READ_TIMEOUT_MS 10 + +/* Instruction type */ +#define CQSPI_INST_TYPE_SINGLE 0 +#define CQSPI_INST_TYPE_DUAL 1 +#define CQSPI_INST_TYPE_QUAD 2 +#define CQSPI_INST_TYPE_OCTAL 3 + +#define CQSPI_DUMMY_CLKS_PER_BYTE 8 +#define CQSPI_DUMMY_BYTES_MAX 4 +#define CQSPI_DUMMY_CLKS_MAX 31 + +#define CQSPI_STIG_DATA_LEN_MAX 8 + +/* Register map */ +#define CQSPI_REG_CONFIG 0x00 +#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0) +#define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL BIT(7) +#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9) +#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10 +#define CQSPI_REG_CONFIG_DMA_MASK BIT(15) +#define CQSPI_REG_CONFIG_BAUD_LSB 19 +#define CQSPI_REG_CONFIG_IDLE_LSB 31 +#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF +#define CQSPI_REG_CONFIG_BAUD_MASK 0xF + +#define CQSPI_REG_RD_INSTR 0x04 +#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0 +#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8 +#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12 +#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16 +#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20 +#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24 +#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3 +#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3 +#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3 +#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F + +#define CQSPI_REG_WR_INSTR 0x08 +#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0 +#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12 +#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16 + +#define CQSPI_REG_DELAY 0x0C +#define CQSPI_REG_DELAY_TSLCH_LSB 0 +#define CQSPI_REG_DELAY_TCHSH_LSB 8 +#define CQSPI_REG_DELAY_TSD2D_LSB 16 +#define CQSPI_REG_DELAY_TSHSL_LSB 24 +#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF +#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF +#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF +#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF + +#define CQSPI_REG_READCAPTURE 0x10 +#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0 +#define CQSPI_REG_READCAPTURE_DELAY_LSB 1 +#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF + +#define CQSPI_REG_SIZE 0x14 +#define CQSPI_REG_SIZE_ADDRESS_LSB 0 +#define CQSPI_REG_SIZE_PAGE_LSB 4 +#define CQSPI_REG_SIZE_BLOCK_LSB 16 +#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF +#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF +#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F + +#define CQSPI_REG_SRAMPARTITION 0x18 +#define CQSPI_REG_INDIRECTTRIGGER 0x1C + +#define CQSPI_REG_DMA 0x20 +#define CQSPI_REG_DMA_SINGLE_LSB 0 +#define CQSPI_REG_DMA_BURST_LSB 8 +#define CQSPI_REG_DMA_SINGLE_MASK 0xFF +#define CQSPI_REG_DMA_BURST_MASK 0xFF + +#define CQSPI_REG_REMAP 0x24 +#define CQSPI_REG_MODE_BIT 0x28 + +#define CQSPI_REG_SDRAMLEVEL 0x2C +#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0 +#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16 +#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF +#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF + +#define CQSPI_REG_IRQSTATUS 0x40 +#define CQSPI_REG_IRQMASK 0x44 + +#define CQSPI_REG_INDIRECTRD 0x60 +#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0) +#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1) +#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5) + +#define CQSPI_REG_INDIRECTRDWATERMARK 0x64 +#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68 +#define CQSPI_REG_INDIRECTRDBYTES 0x6C + +#define CQSPI_REG_CMDCTRL 0x90 +#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0) +#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1) +#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12 +#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15 +#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16 +#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19 +#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20 +#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23 +#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24 +#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7 +#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3 +#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7 + +#define CQSPI_REG_INDIRECTWR 0x70 +#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0) +#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1) +#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5) + +#define CQSPI_REG_INDIRECTWRWATERMARK 0x74 +#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78 +#define CQSPI_REG_INDIRECTWRBYTES 0x7C + +#define CQSPI_REG_CMDADDRESS 0x94 +#define CQSPI_REG_CMDREADDATALOWER 0xA0 +#define CQSPI_REG_CMDREADDATAUPPER 0xA4 +#define CQSPI_REG_CMDWRITEDATALOWER 0xA8 +#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC + +/* Interrupt status bits */ +#define CQSPI_REG_IRQ_MODE_ERR BIT(0) +#define CQSPI_REG_IRQ_UNDERFLOW BIT(1) +#define CQSPI_REG_IRQ_IND_COMP BIT(2) +#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3) +#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4) +#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5) +#define CQSPI_REG_IRQ_WATERMARK BIT(6) +#define CQSPI_REG_IRQ_IND_SRAM_FULL BIT(12) + +#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \ + CQSPI_REG_IRQ_IND_SRAM_FULL | \ + CQSPI_REG_IRQ_IND_COMP) + +#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \ + CQSPI_REG_IRQ_WATERMARK | \ + CQSPI_REG_IRQ_UNDERFLOW) + +#define CQSPI_IRQ_STATUS_MASK 0x1FFFF + +static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr) +{ + u32 val; + + return readl_relaxed_poll_timeout(reg, val, + (((clr ? ~val : val) & mask) == mask), + 10, CQSPI_TIMEOUT_MS * 1000); +} + +static bool cqspi_is_idle(struct cqspi_st *cqspi) +{ + u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG); + + return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB); +} + +static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi) +{ + u32 reg = readl(cqspi->iobase + CQSPI_REG_SDRAMLEVEL); + + reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB; + return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK; +} + +static irqreturn_t cqspi_irq_handler(int this_irq, void *dev) +{ + struct cqspi_st *cqspi = dev; + unsigned int irq_status; + + /* Read interrupt status */ + irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS); + + /* Clear interrupt */ + writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS); + + irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR; + + if (irq_status) + complete(&cqspi->transfer_complete); + + return IRQ_HANDLED; +} + +static unsigned int cqspi_calc_rdreg(struct cqspi_flash_pdata *f_pdata) +{ + u32 rdreg = 0; + + rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB; + rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB; + rdreg |= f_pdata->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; + + return rdreg; +} + +static int cqspi_wait_idle(struct cqspi_st *cqspi) +{ + const unsigned int poll_idle_retry = 3; + unsigned int count = 0; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS); + while (1) { + /* + * Read few times in succession to ensure the controller + * is indeed idle, that is, the bit does not transition + * low again. + */ + if (cqspi_is_idle(cqspi)) + count++; + else + count = 0; + + if (count >= poll_idle_retry) + return 0; + + if (time_after(jiffies, timeout)) { + /* Timeout, in busy mode. */ + dev_err(&cqspi->pdev->dev, + "QSPI is still busy after %dms timeout.\n", + CQSPI_TIMEOUT_MS); + return -ETIMEDOUT; + } + + cpu_relax(); + } +} + +static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg) +{ + void __iomem *reg_base = cqspi->iobase; + int ret; + + /* Write the CMDCTRL without start execution. */ + writel(reg, reg_base + CQSPI_REG_CMDCTRL); + /* Start execute */ + reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK; + writel(reg, reg_base + CQSPI_REG_CMDCTRL); + + /* Polling for completion. */ + ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL, + CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1); + if (ret) { + dev_err(&cqspi->pdev->dev, + "Flash command execution timed out.\n"); + return ret; + } + + /* Polling QSPI idle status. */ + return cqspi_wait_idle(cqspi); +} + +static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + void __iomem *reg_base = cqspi->iobase; + u8 *rxbuf = op->data.buf.in; + u8 opcode = op->cmd.opcode; + size_t n_rx = op->data.nbytes; + unsigned int rdreg; + unsigned int reg; + size_t read_len; + int status; + + if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) { + dev_err(&cqspi->pdev->dev, + "Invalid input argument, len %zu rxbuf 0x%p\n", + n_rx, rxbuf); + return -EINVAL; + } + + reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; + + rdreg = cqspi_calc_rdreg(f_pdata); + writel(rdreg, reg_base + CQSPI_REG_RD_INSTR); + + reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); + + /* 0 means 1 byte. */ + reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) + << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); + status = cqspi_exec_flash_cmd(cqspi, reg); + if (status) + return status; + + reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER); + + /* Put the read value into rx_buf */ + read_len = (n_rx > 4) ? 4 : n_rx; + memcpy(rxbuf, ®, read_len); + rxbuf += read_len; + + if (n_rx > 4) { + reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER); + + read_len = n_rx - read_len; + memcpy(rxbuf, ®, read_len); + } + + return 0; +} + +static int cqspi_command_write(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + void __iomem *reg_base = cqspi->iobase; + const u8 opcode = op->cmd.opcode; + const u8 *txbuf = op->data.buf.out; + size_t n_tx = op->data.nbytes; + unsigned int reg; + unsigned int data; + size_t write_len; + + if (n_tx > CQSPI_STIG_DATA_LEN_MAX || (n_tx && !txbuf)) { + dev_err(&cqspi->pdev->dev, + "Invalid input argument, cmdlen %zu txbuf 0x%p\n", + n_tx, txbuf); + return -EINVAL; + } + + reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; + + if (op->addr.nbytes) { + reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); + reg |= ((op->addr.nbytes - 1) & + CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) + << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; + + writel(op->addr.val, reg_base + CQSPI_REG_CMDADDRESS); + } + + if (n_tx) { + reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB); + reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) + << CQSPI_REG_CMDCTRL_WR_BYTES_LSB; + data = 0; + write_len = (n_tx > 4) ? 4 : n_tx; + memcpy(&data, txbuf, write_len); + txbuf += write_len; + writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER); + + if (n_tx > 4) { + data = 0; + write_len = n_tx - 4; + memcpy(&data, txbuf, write_len); + writel(data, reg_base + CQSPI_REG_CMDWRITEDATAUPPER); + } + } + + return cqspi_exec_flash_cmd(cqspi, reg); +} + +static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + void __iomem *reg_base = cqspi->iobase; + unsigned int dummy_clk = 0; + unsigned int reg; + + reg = op->cmd.opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB; + reg |= cqspi_calc_rdreg(f_pdata); + + /* Setup dummy clock cycles */ + dummy_clk = op->dummy.nbytes * 8; + if (dummy_clk > CQSPI_DUMMY_CLKS_MAX) + dummy_clk = CQSPI_DUMMY_CLKS_MAX; + + if (dummy_clk) + reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK) + << CQSPI_REG_RD_INSTR_DUMMY_LSB; + + writel(reg, reg_base + CQSPI_REG_RD_INSTR); + + /* Set address width */ + reg = readl(reg_base + CQSPI_REG_SIZE); + reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; + reg |= (op->addr.nbytes - 1); + writel(reg, reg_base + CQSPI_REG_SIZE); + return 0; +} + +static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, + u8 *rxbuf, loff_t from_addr, + const size_t n_rx) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + struct device *dev = &cqspi->pdev->dev; + void __iomem *reg_base = cqspi->iobase; + void __iomem *ahb_base = cqspi->ahb_base; + unsigned int remaining = n_rx; + unsigned int mod_bytes = n_rx % 4; + unsigned int bytes_to_read = 0; + u8 *rxbuf_end = rxbuf + n_rx; + int ret = 0; + + writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); + writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES); + + /* Clear all interrupts. */ + writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); + + writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK); + + reinit_completion(&cqspi->transfer_complete); + writel(CQSPI_REG_INDIRECTRD_START_MASK, + reg_base + CQSPI_REG_INDIRECTRD); + + while (remaining > 0) { + if (!wait_for_completion_timeout(&cqspi->transfer_complete, + msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) + ret = -ETIMEDOUT; + + bytes_to_read = cqspi_get_rd_sram_level(cqspi); + + if (ret && bytes_to_read == 0) { + dev_err(dev, "Indirect read timeout, no bytes\n"); + goto failrd; + } + + while (bytes_to_read != 0) { + unsigned int word_remain = round_down(remaining, 4); + + bytes_to_read *= cqspi->fifo_width; + bytes_to_read = bytes_to_read > remaining ? + remaining : bytes_to_read; + bytes_to_read = round_down(bytes_to_read, 4); + /* Read 4 byte word chunks then single bytes */ + if (bytes_to_read) { + ioread32_rep(ahb_base, rxbuf, + (bytes_to_read / 4)); + } else if (!word_remain && mod_bytes) { + unsigned int temp = ioread32(ahb_base); + + bytes_to_read = mod_bytes; + memcpy(rxbuf, &temp, min((unsigned int) + (rxbuf_end - rxbuf), + bytes_to_read)); + } + rxbuf += bytes_to_read; + remaining -= bytes_to_read; + bytes_to_read = cqspi_get_rd_sram_level(cqspi); + } + + if (remaining > 0) + reinit_completion(&cqspi->transfer_complete); + } + + /* Check indirect done status */ + ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD, + CQSPI_REG_INDIRECTRD_DONE_MASK, 0); + if (ret) { + dev_err(dev, "Indirect read completion error (%i)\n", ret); + goto failrd; + } + + /* Disable interrupt */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Clear indirect completion status */ + writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD); + + return 0; + +failrd: + /* Disable interrupt */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Cancel the indirect read */ + writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, + reg_base + CQSPI_REG_INDIRECTRD); + return ret; +} + +static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + unsigned int reg; + struct cqspi_st *cqspi = f_pdata->cqspi; + void __iomem *reg_base = cqspi->iobase; + + /* Set opcode. */ + reg = op->cmd.opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB; + writel(reg, reg_base + CQSPI_REG_WR_INSTR); + reg = cqspi_calc_rdreg(f_pdata); + writel(reg, reg_base + CQSPI_REG_RD_INSTR); + + reg = readl(reg_base + CQSPI_REG_SIZE); + reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; + reg |= (op->addr.nbytes - 1); + writel(reg, reg_base + CQSPI_REG_SIZE); + return 0; +} + +static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, + loff_t to_addr, const u8 *txbuf, + const size_t n_tx) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + struct device *dev = &cqspi->pdev->dev; + void __iomem *reg_base = cqspi->iobase; + unsigned int remaining = n_tx; + unsigned int write_bytes; + int ret; + + writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR); + writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES); + + /* Clear all interrupts. */ + writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); + + writel(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK); + + reinit_completion(&cqspi->transfer_complete); + writel(CQSPI_REG_INDIRECTWR_START_MASK, + reg_base + CQSPI_REG_INDIRECTWR); + /* + * As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access + * Controller programming sequence, couple of cycles of + * QSPI_REF_CLK delay is required for the above bit to + * be internally synchronized by the QSPI module. Provide 5 + * cycles of delay. + */ + if (cqspi->wr_delay) + ndelay(cqspi->wr_delay); + + while (remaining > 0) { + size_t write_words, mod_bytes; + + write_bytes = remaining; + write_words = write_bytes / 4; + mod_bytes = write_bytes % 4; + /* Write 4 bytes at a time then single bytes. */ + if (write_words) { + iowrite32_rep(cqspi->ahb_base, txbuf, write_words); + txbuf += (write_words * 4); + } + if (mod_bytes) { + unsigned int temp = 0xFFFFFFFF; + + memcpy(&temp, txbuf, mod_bytes); + iowrite32(temp, cqspi->ahb_base); + txbuf += mod_bytes; + } + + if (!wait_for_completion_timeout(&cqspi->transfer_complete, + msecs_to_jiffies(CQSPI_TIMEOUT_MS))) { + dev_err(dev, "Indirect write timeout\n"); + ret = -ETIMEDOUT; + goto failwr; + } + + remaining -= write_bytes; + + if (remaining > 0) + reinit_completion(&cqspi->transfer_complete); + } + + /* Check indirect done status */ + ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR, + CQSPI_REG_INDIRECTWR_DONE_MASK, 0); + if (ret) { + dev_err(dev, "Indirect write completion error (%i)\n", ret); + goto failwr; + } + + /* Disable interrupt. */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Clear indirect completion status */ + writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR); + + cqspi_wait_idle(cqspi); + + return 0; + +failwr: + /* Disable interrupt. */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Cancel the indirect write */ + writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, + reg_base + CQSPI_REG_INDIRECTWR); + return ret; +} + +static void cqspi_chipselect(struct cqspi_flash_pdata *f_pdata) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + void __iomem *reg_base = cqspi->iobase; + unsigned int chip_select = f_pdata->cs; + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + if (cqspi->is_decoded_cs) { + reg |= CQSPI_REG_CONFIG_DECODE_MASK; + } else { + reg &= ~CQSPI_REG_CONFIG_DECODE_MASK; + + /* Convert CS if without decoder. + * CS0 to 4b'1110 + * CS1 to 4b'1101 + * CS2 to 4b'1011 + * CS3 to 4b'0111 + */ + chip_select = 0xF & ~(1 << chip_select); + } + + reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK + << CQSPI_REG_CONFIG_CHIPSELECT_LSB); + reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK) + << CQSPI_REG_CONFIG_CHIPSELECT_LSB; + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + +static unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz, + const unsigned int ns_val) +{ + unsigned int ticks; + + ticks = ref_clk_hz / 1000; /* kHz */ + ticks = DIV_ROUND_UP(ticks * ns_val, 1000000); + + return ticks; +} + +static void cqspi_delay(struct cqspi_flash_pdata *f_pdata) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + void __iomem *iobase = cqspi->iobase; + const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz; + unsigned int tshsl, tchsh, tslch, tsd2d; + unsigned int reg; + unsigned int tsclk; + + /* calculate the number of ref ticks for one sclk tick */ + tsclk = DIV_ROUND_UP(ref_clk_hz, cqspi->sclk); + + tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns); + /* this particular value must be at least one sclk */ + if (tshsl < tsclk) + tshsl = tsclk; + + tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns); + tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns); + tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns); + + reg = (tshsl & CQSPI_REG_DELAY_TSHSL_MASK) + << CQSPI_REG_DELAY_TSHSL_LSB; + reg |= (tchsh & CQSPI_REG_DELAY_TCHSH_MASK) + << CQSPI_REG_DELAY_TCHSH_LSB; + reg |= (tslch & CQSPI_REG_DELAY_TSLCH_MASK) + << CQSPI_REG_DELAY_TSLCH_LSB; + reg |= (tsd2d & CQSPI_REG_DELAY_TSD2D_MASK) + << CQSPI_REG_DELAY_TSD2D_LSB; + writel(reg, iobase + CQSPI_REG_DELAY); +} + +static void cqspi_config_baudrate_div(struct cqspi_st *cqspi) +{ + const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz; + void __iomem *reg_base = cqspi->iobase; + u32 reg, div; + + /* Recalculate the baudrate divisor based on QSPI specification. */ + div = DIV_ROUND_UP(ref_clk_hz, 2 * cqspi->sclk) - 1; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB); + reg |= (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB; + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + +static void cqspi_readdata_capture(struct cqspi_st *cqspi, + const bool bypass, + const unsigned int delay) +{ + void __iomem *reg_base = cqspi->iobase; + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_READCAPTURE); + + if (bypass) + reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); + else + reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); + + reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK + << CQSPI_REG_READCAPTURE_DELAY_LSB); + + reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK) + << CQSPI_REG_READCAPTURE_DELAY_LSB; + + writel(reg, reg_base + CQSPI_REG_READCAPTURE); +} + +static void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable) +{ + void __iomem *reg_base = cqspi->iobase; + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + + if (enable) + reg |= CQSPI_REG_CONFIG_ENABLE_MASK; + else + reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK; + + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + +static void cqspi_configure(struct cqspi_flash_pdata *f_pdata, + unsigned long sclk) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + int switch_cs = (cqspi->current_cs != f_pdata->cs); + int switch_ck = (cqspi->sclk != sclk); + + if (switch_cs || switch_ck) + cqspi_controller_enable(cqspi, 0); + + /* Switch chip select. */ + if (switch_cs) { + cqspi->current_cs = f_pdata->cs; + cqspi_chipselect(f_pdata); + } + + /* Setup baudrate divisor and delays */ + if (switch_ck) { + cqspi->sclk = sclk; + cqspi_config_baudrate_div(cqspi); + cqspi_delay(f_pdata); + cqspi_readdata_capture(cqspi, !cqspi->rclk_en, + f_pdata->read_delay); + } + + if (switch_cs || switch_ck) + cqspi_controller_enable(cqspi, 1); +} + +static int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE; + f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE; + f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; + + if (op->data.dir == SPI_MEM_DATA_IN) { + switch (op->data.buswidth) { + case 1: + f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; + break; + case 2: + f_pdata->data_width = CQSPI_INST_TYPE_DUAL; + break; + case 4: + f_pdata->data_width = CQSPI_INST_TYPE_QUAD; + break; + case 8: + f_pdata->data_width = CQSPI_INST_TYPE_OCTAL; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + loff_t to = op->addr.val; + size_t len = op->data.nbytes; + const u_char *buf = op->data.buf.out; + int ret; + + ret = cqspi_set_protocol(f_pdata, op); + if (ret) + return ret; + + ret = cqspi_write_setup(f_pdata, op); + if (ret) + return ret; + + if (cqspi->use_direct_mode && ((to + len) <= cqspi->ahb_size)) { + memcpy_toio(cqspi->ahb_base + to, buf, len); + return cqspi_wait_idle(cqspi); + } + + return cqspi_indirect_write_execute(f_pdata, to, buf, len); +} + +static void cqspi_rx_dma_callback(void *param) +{ + struct cqspi_st *cqspi = param; + + complete(&cqspi->rx_dma_complete); +} + +static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, + u_char *buf, loff_t from, size_t len) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + struct device *dev = &cqspi->pdev->dev; + enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + dma_addr_t dma_src = (dma_addr_t)cqspi->mmap_phys_base + from; + int ret = 0; + struct dma_async_tx_descriptor *tx; + dma_cookie_t cookie; + dma_addr_t dma_dst; + + if (!cqspi->rx_chan || !virt_addr_valid(buf)) { + memcpy_fromio(buf, cqspi->ahb_base + from, len); + return 0; + } + + dma_dst = dma_map_single(dev, buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, dma_dst)) { + dev_err(dev, "dma mapping failed\n"); + return -ENOMEM; + } + tx = dmaengine_prep_dma_memcpy(cqspi->rx_chan, dma_dst, dma_src, + len, flags); + if (!tx) { + dev_err(dev, "device_prep_dma_memcpy error\n"); + ret = -EIO; + goto err_unmap; + } + + tx->callback = cqspi_rx_dma_callback; + tx->callback_param = cqspi; + cookie = tx->tx_submit(tx); + reinit_completion(&cqspi->rx_dma_complete); + + ret = dma_submit_error(cookie); + if (ret) { + dev_err(dev, "dma_submit_error %d\n", cookie); + ret = -EIO; + goto err_unmap; + } + + dma_async_issue_pending(cqspi->rx_chan); + if (!wait_for_completion_timeout(&cqspi->rx_dma_complete, + msecs_to_jiffies(len))) { + dmaengine_terminate_sync(cqspi->rx_chan); + dev_err(dev, "DMA wait_for_completion_timeout\n"); + ret = -ETIMEDOUT; + goto err_unmap; + } + +err_unmap: + dma_unmap_single(dev, dma_dst, len, DMA_FROM_DEVICE); + + return ret; +} + +static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + loff_t from = op->addr.val; + size_t len = op->data.nbytes; + u_char *buf = op->data.buf.in; + int ret; + + ret = cqspi_set_protocol(f_pdata, op); + if (ret) + return ret; + + ret = cqspi_read_setup(f_pdata, op); + if (ret) + return ret; + + if (cqspi->use_direct_mode && ((from + len) <= cqspi->ahb_size)) + return cqspi_direct_read_execute(f_pdata, buf, from, len); + + return cqspi_indirect_read_execute(f_pdata, buf, from, len); +} + +static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master); + struct cqspi_flash_pdata *f_pdata; + + f_pdata = &cqspi->f_pdata[mem->spi->chip_select]; + cqspi_configure(f_pdata, mem->spi->max_speed_hz); + + if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) { + if (!op->addr.nbytes) + return cqspi_command_read(f_pdata, op); + + return cqspi_read(f_pdata, op); + } + + if (!op->addr.nbytes || !op->data.buf.out) + return cqspi_command_write(f_pdata, op); + + return cqspi_write(f_pdata, op); +} + +static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + int ret; + + ret = cqspi_mem_process(mem, op); + if (ret) + dev_err(&mem->spi->dev, "operation failed with %d\n", ret); + + return ret; +} + +static int cqspi_of_get_flash_pdata(struct platform_device *pdev, + struct cqspi_flash_pdata *f_pdata, + struct device_node *np) +{ + if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) { + dev_err(&pdev->dev, "couldn't determine read-delay\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) { + dev_err(&pdev->dev, "couldn't determine tshsl-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) { + dev_err(&pdev->dev, "couldn't determine tsd2d-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) { + dev_err(&pdev->dev, "couldn't determine tchsh-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) { + dev_err(&pdev->dev, "couldn't determine tslch-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) { + dev_err(&pdev->dev, "couldn't determine spi-max-frequency\n"); + return -ENXIO; + } + + return 0; +} + +static int cqspi_of_get_pdata(struct cqspi_st *cqspi) +{ + struct device *dev = &cqspi->pdev->dev; + struct device_node *np = dev->of_node; + + cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs"); + + if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) { + dev_err(dev, "couldn't determine fifo-depth\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) { + dev_err(dev, "couldn't determine fifo-width\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,trigger-address", + &cqspi->trigger_address)) { + dev_err(dev, "couldn't determine trigger-address\n"); + return -ENXIO; + } + + cqspi->rclk_en = of_property_read_bool(np, "cdns,rclk-en"); + + return 0; +} + +static void cqspi_controller_init(struct cqspi_st *cqspi) +{ + u32 reg; + + cqspi_controller_enable(cqspi, 0); + + /* Configure the remap address register, no remap */ + writel(0, cqspi->iobase + CQSPI_REG_REMAP); + + /* Disable all interrupts. */ + writel(0, cqspi->iobase + CQSPI_REG_IRQMASK); + + /* Configure the SRAM split to 1:1 . */ + writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION); + + /* Load indirect trigger address. */ + writel(cqspi->trigger_address, + cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER); + + /* Program read watermark -- 1/2 of the FIFO. */ + writel(cqspi->fifo_depth * cqspi->fifo_width / 2, + cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK); + /* Program write watermark -- 1/8 of the FIFO. */ + writel(cqspi->fifo_depth * cqspi->fifo_width / 8, + cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK); + + /* Enable Direct Access Controller */ + reg = readl(cqspi->iobase + CQSPI_REG_CONFIG); + reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL; + writel(reg, cqspi->iobase + CQSPI_REG_CONFIG); + + cqspi_controller_enable(cqspi, 1); +} + +static int cqspi_request_mmap_dma(struct cqspi_st *cqspi) +{ + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + + cqspi->rx_chan = dma_request_chan_by_mask(&mask); + if (IS_ERR(cqspi->rx_chan)) { + int ret = PTR_ERR(cqspi->rx_chan); + + if (ret != -EPROBE_DEFER) + dev_err(&cqspi->pdev->dev, "No Rx DMA available\n"); + cqspi->rx_chan = NULL; + return ret; + } + init_completion(&cqspi->rx_dma_complete); + + return 0; +} + +static const struct spi_controller_mem_ops cqspi_mem_ops = { + .exec_op = cqspi_exec_mem_op, +}; + +static int cqspi_setup_flash(struct cqspi_st *cqspi) +{ + struct platform_device *pdev = cqspi->pdev; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct cqspi_flash_pdata *f_pdata; + unsigned int cs; + int ret; + + /* Get flash device data */ + for_each_available_child_of_node(dev->of_node, np) { + ret = of_property_read_u32(np, "reg", &cs); + if (ret) { + dev_err(dev, "Couldn't determine chip select.\n"); + return ret; + } + + if (cs >= CQSPI_MAX_CHIPSELECT) { + dev_err(dev, "Chip select %d out of range.\n", cs); + return -EINVAL; + } + + f_pdata = &cqspi->f_pdata[cs]; + f_pdata->cqspi = cqspi; + f_pdata->cs = cs; + + ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np); + if (ret) + return ret; + } + + return 0; +} + +static int cqspi_probe(struct platform_device *pdev) +{ + const struct cqspi_driver_platdata *ddata; + struct reset_control *rstc, *rstc_ocp; + struct device *dev = &pdev->dev; + struct spi_master *master; + struct resource *res_ahb; + struct cqspi_st *cqspi; + struct resource *res; + int ret; + int irq; + + master = spi_alloc_master(&pdev->dev, sizeof(*cqspi)); + if (!master) { + dev_err(&pdev->dev, "spi_alloc_master failed\n"); + return -ENOMEM; + } + master->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL; + master->mem_ops = &cqspi_mem_ops; + master->dev.of_node = pdev->dev.of_node; + + cqspi = spi_master_get_devdata(master); + + cqspi->pdev = pdev; + + /* Obtain configuration from OF. */ + ret = cqspi_of_get_pdata(cqspi); + if (ret) { + dev_err(dev, "Cannot get mandatory OF data.\n"); + ret = -ENODEV; + goto probe_master_put; + } + + /* Obtain QSPI clock. */ + cqspi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(cqspi->clk)) { + dev_err(dev, "Cannot claim QSPI clock.\n"); + ret = PTR_ERR(cqspi->clk); + goto probe_master_put; + } + + /* Obtain and remap controller address. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cqspi->iobase = devm_ioremap_resource(dev, res); + if (IS_ERR(cqspi->iobase)) { + dev_err(dev, "Cannot remap controller address.\n"); + ret = PTR_ERR(cqspi->iobase); + goto probe_master_put; + } + + /* Obtain and remap AHB address. */ + res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1); + cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb); + if (IS_ERR(cqspi->ahb_base)) { + dev_err(dev, "Cannot remap AHB address.\n"); + ret = PTR_ERR(cqspi->ahb_base); + goto probe_master_put; + } + cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start; + cqspi->ahb_size = resource_size(res_ahb); + + init_completion(&cqspi->transfer_complete); + + /* Obtain IRQ line. */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = -ENXIO; + goto probe_master_put; + } + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + goto probe_master_put; + } + + ret = clk_prepare_enable(cqspi->clk); + if (ret) { + dev_err(dev, "Cannot enable QSPI clock.\n"); + goto probe_clk_failed; + } + + /* Obtain QSPI reset control */ + rstc = devm_reset_control_get_optional_exclusive(dev, "qspi"); + if (IS_ERR(rstc)) { + dev_err(dev, "Cannot get QSPI reset.\n"); + goto probe_reset_failed; + } + + rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp"); + if (IS_ERR(rstc_ocp)) { + dev_err(dev, "Cannot get QSPI OCP reset.\n"); + goto probe_reset_failed; + } + + reset_control_assert(rstc); + reset_control_deassert(rstc); + + reset_control_assert(rstc_ocp); + reset_control_deassert(rstc_ocp); + + cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); + ddata = of_device_get_match_data(dev); + if (ddata) { + if (ddata->quirks & CQSPI_NEEDS_WR_DELAY) + cqspi->wr_delay = 5 * DIV_ROUND_UP(NSEC_PER_SEC, + cqspi->master_ref_clk_hz); + if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL) + master->mode_bits |= SPI_RX_OCTAL; + if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE)) + cqspi->use_direct_mode = true; + } + + ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0, + pdev->name, cqspi); + if (ret) { + dev_err(dev, "Cannot request IRQ.\n"); + goto probe_reset_failed; + } + + cqspi_wait_idle(cqspi); + cqspi_controller_init(cqspi); + cqspi->current_cs = -1; + cqspi->sclk = 0; + + ret = cqspi_setup_flash(cqspi); + if (ret) { + dev_err(dev, "failed to setup flash parameters %d\n", ret); + goto probe_setup_failed; + } + + if (cqspi->use_direct_mode) { + ret = cqspi_request_mmap_dma(cqspi); + if (ret == -EPROBE_DEFER) + goto probe_setup_failed; + } + + ret = devm_spi_register_master(dev, master); + if (ret) { + dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret); + goto probe_setup_failed; + } + + return 0; +probe_setup_failed: + cqspi_controller_enable(cqspi, 0); +probe_reset_failed: + clk_disable_unprepare(cqspi->clk); +probe_clk_failed: + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); +probe_master_put: + spi_master_put(master); + return ret; +} + +static int cqspi_remove(struct platform_device *pdev) +{ + struct cqspi_st *cqspi = platform_get_drvdata(pdev); + + cqspi_controller_enable(cqspi, 0); + + if (cqspi->rx_chan) + dma_release_channel(cqspi->rx_chan); + + clk_disable_unprepare(cqspi->clk); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int cqspi_suspend(struct device *dev) +{ + struct cqspi_st *cqspi = dev_get_drvdata(dev); + + cqspi_controller_enable(cqspi, 0); + return 0; +} + +static int cqspi_resume(struct device *dev) +{ + struct cqspi_st *cqspi = dev_get_drvdata(dev); + + cqspi_controller_enable(cqspi, 1); + return 0; +} + +static const struct dev_pm_ops cqspi__dev_pm_ops = { + .suspend = cqspi_suspend, + .resume = cqspi_resume, +}; + +#define CQSPI_DEV_PM_OPS (&cqspi__dev_pm_ops) +#else +#define CQSPI_DEV_PM_OPS NULL +#endif + +static const struct cqspi_driver_platdata cdns_qspi = { + .quirks = CQSPI_DISABLE_DAC_MODE, +}; + +static const struct cqspi_driver_platdata k2g_qspi = { + .quirks = CQSPI_NEEDS_WR_DELAY, +}; + +static const struct cqspi_driver_platdata am654_ospi = { + .hwcaps_mask = CQSPI_SUPPORTS_OCTAL, + .quirks = CQSPI_NEEDS_WR_DELAY, +}; + +static const struct of_device_id cqspi_dt_ids[] = { + { + .compatible = "cdns,qspi-nor", + .data = &cdns_qspi, + }, + { + .compatible = "ti,k2g-qspi", + .data = &k2g_qspi, + }, + { + .compatible = "ti,am654-ospi", + .data = &am654_ospi, + }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, cqspi_dt_ids); + +static struct platform_driver cqspi_platform_driver = { + .probe = cqspi_probe, + .remove = cqspi_remove, + .driver = { + .name = CQSPI_NAME, + .pm = CQSPI_DEV_PM_OPS, + .of_match_table = cqspi_dt_ids, + }, +}; + +module_platform_driver(cqspi_platform_driver); + +MODULE_DESCRIPTION("Cadence QSPI Controller Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" CQSPI_NAME); +MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>"); +MODULE_AUTHOR("Graham Moore <grmoore@opensource.altera.com>"); +MODULE_AUTHOR("Vadivel Murugan R <vadivel.muruganx.ramuthevar@intel.com>"); +MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>"); diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 82a0ee09cbe1..2b6b9c1ad9d0 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -556,7 +556,7 @@ static int cdns_spi_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; master->set_cs = cdns_spi_chipselect; master->auto_runtime_pm = true; - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; /* Set to default valid value */ master->max_speed_hz = clk_get_rate(xspi->ref_clk) / 4; diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c index fd6b9caffaf0..60c0d6934654 100644 --- a/drivers/spi/spi-cavium-thunderx.c +++ b/drivers/spi/spi-cavium-thunderx.c @@ -64,6 +64,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev, p->sys_freq = SYS_FREQ_DEFAULT; dev_info(dev, "Set system clock to %u\n", p->sys_freq); + master->flags = SPI_MASTER_HALF_DUPLEX; master->num_chipselect = 4; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE; diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index f80e06c87fbe..8996115ce736 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -387,7 +387,7 @@ static int mcfqspi_probe(struct platform_device *pdev) status = PTR_ERR(mcfqspi->clk); goto fail0; } - clk_enable(mcfqspi->clk); + clk_prepare_enable(mcfqspi->clk); master->bus_num = pdata->bus_num; master->num_chipselect = pdata->num_chipselect; @@ -425,7 +425,7 @@ fail2: pm_runtime_disable(&pdev->dev); mcfqspi_cs_teardown(mcfqspi); fail1: - clk_disable(mcfqspi->clk); + clk_disable_unprepare(mcfqspi->clk); fail0: spi_master_put(master); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index f71c497393a6..c329a27c16ac 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -236,7 +236,8 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) /** * davinci_spi_get_prescale - Calculates the correct prescale value - * @maxspeed_hz: the maximum rate the SPI clock can run at + * @dspi: the controller data + * @max_speed_hz: the maximum rate the SPI clock can run at * * This function calculates the prescale value that generates a clock rate * less than or equal to the specified maximum. @@ -711,7 +712,7 @@ err_desc: /** * dummy_thread_fn - dummy thread function * @irq: IRQ number for this SPI Master - * @context_data: structure for SPI Master controller davinci_spi + * @data: structure for SPI Master controller davinci_spi * * This is to satisfy the request_threaded_irq() API so that the irq * handler is called in interrupt context. @@ -724,7 +725,7 @@ static irqreturn_t dummy_thread_fn(s32 irq, void *data) /** * davinci_spi_irq - Interrupt handler for SPI Master Controller * @irq: IRQ number for this SPI Master - * @context_data: structure for SPI Master controller davinci_spi + * @data: structure for SPI Master controller davinci_spi * * ISR will determine that interrupt arrives either for READ or WRITE command. * According to command it will do the appropriate action. It will check diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 8c854b187b1d..aa676559d273 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -10,7 +10,7 @@ * * For more information about the SPI controller see documentation on Cirrus * Logic web site: - * http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf + * https://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf */ #include <linux/io.h> @@ -214,7 +214,7 @@ static void ep93xx_do_read(struct spi_master *master) /** * ep93xx_spi_read_write() - perform next RX/TX transfer - * @espi: ep93xx SPI controller struct + * @master: SPI master * * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If * called several times, the whole transfer will be completed. Returns diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 1552b28b9515..85a5c952389a 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -11,7 +11,6 @@ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> @@ -19,11 +18,9 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/platform_data/dma-imx.h> -#include <linux/platform_data/spi-imx.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/spi/spi.h> @@ -101,6 +98,7 @@ struct fsl_lpspi_data { struct clk *clk_ipg; struct clk *clk_per; bool is_slave; + bool is_only_cs1; bool is_first_byte; void *rx_buf; @@ -122,8 +120,6 @@ struct fsl_lpspi_data { bool usedma; struct completion dma_rx_completion; struct completion dma_tx_completion; - - int chipselect[]; }; static const struct of_device_id fsl_lpspi_dt_ids[] = { @@ -224,20 +220,6 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller) return 0; } -static int fsl_lpspi_prepare_message(struct spi_controller *controller, - struct spi_message *msg) -{ - struct fsl_lpspi_data *fsl_lpspi = - spi_controller_get_devdata(controller); - struct spi_device *spi = msg->spi; - int gpio = fsl_lpspi->chipselect[spi->chip_select]; - - if (gpio_is_valid(gpio)) - gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); - - return 0; -} - static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi) { u8 txfifo_cnt; @@ -276,10 +258,9 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi) temp |= fsl_lpspi->config.bpw - 1; temp |= (fsl_lpspi->config.mode & 0x3) << 30; + temp |= (fsl_lpspi->config.chip_select & 0x3) << 24; if (!fsl_lpspi->is_slave) { temp |= fsl_lpspi->config.prescale << 27; - temp |= (fsl_lpspi->config.chip_select & 0x3) << 24; - /* * Set TCR_CONT will keep SS asserted after current transfer. * For the first transfer, clear TCR_CONTC to assert SS. @@ -440,7 +421,10 @@ static int fsl_lpspi_setup_transfer(struct spi_controller *controller, fsl_lpspi->config.mode = spi->mode; fsl_lpspi->config.bpw = t->bits_per_word; fsl_lpspi->config.speed_hz = t->speed_hz; - fsl_lpspi->config.chip_select = spi->chip_select; + if (fsl_lpspi->is_only_cs1) + fsl_lpspi->config.chip_select = 1; + else + fsl_lpspi->config.chip_select = spi->chip_select; if (!fsl_lpspi->config.speed_hz) fsl_lpspi->config.speed_hz = spi->max_speed_hz; @@ -831,13 +815,10 @@ static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi) static int fsl_lpspi_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct fsl_lpspi_data *fsl_lpspi; struct spi_controller *controller; - struct spi_imx_master *lpspi_platform_info = - dev_get_platdata(&pdev->dev); struct resource *res; - int i, ret, irq; + int ret, irq; u32 temp; bool is_slave; @@ -857,6 +838,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev) fsl_lpspi = spi_controller_get_devdata(controller); fsl_lpspi->dev = &pdev->dev; fsl_lpspi->is_slave = is_slave; + fsl_lpspi->is_only_cs1 = of_property_read_bool((&pdev->dev)->of_node, + "fsl,spi-only-use-cs1-sel"); controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); controller->transfer_one = fsl_lpspi_transfer_one; @@ -867,35 +850,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev) controller->dev.of_node = pdev->dev.of_node; controller->bus_num = pdev->id; controller->slave_abort = fsl_lpspi_slave_abort; - - ret = devm_spi_register_controller(&pdev->dev, controller); - if (ret < 0) { - dev_err(&pdev->dev, "spi_register_controller error.\n"); - goto out_controller_put; - } - - if (!fsl_lpspi->is_slave) { - for (i = 0; i < controller->num_chipselect; i++) { - int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); - - if (!gpio_is_valid(cs_gpio) && lpspi_platform_info) - cs_gpio = lpspi_platform_info->chipselect[i]; - - fsl_lpspi->chipselect[i] = cs_gpio; - if (!gpio_is_valid(cs_gpio)) - continue; - - ret = devm_gpio_request(&pdev->dev, - fsl_lpspi->chipselect[i], - DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, "can't get cs gpios\n"); - goto out_controller_put; - } - } - controller->cs_gpios = fsl_lpspi->chipselect; - controller->prepare_message = fsl_lpspi_prepare_message; - } + if (!fsl_lpspi->is_slave) + controller->use_gpio_descriptors = true; init_completion(&fsl_lpspi->xfer_done); @@ -954,10 +910,21 @@ static int fsl_lpspi_probe(struct platform_device *pdev) if (ret < 0) dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret); + ret = devm_spi_register_controller(&pdev->dev, controller); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_controller error.\n"); + goto out_pm_get; + } + + pm_runtime_mark_last_busy(fsl_lpspi->dev); + pm_runtime_put_autosuspend(fsl_lpspi->dev); + return 0; out_pm_get: - pm_runtime_put_noidle(fsl_lpspi->dev); + pm_runtime_dont_use_autosuspend(fsl_lpspi->dev); + pm_runtime_put_sync(fsl_lpspi->dev); + pm_runtime_disable(fsl_lpspi->dev); out_controller_put: spi_controller_put(controller); diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index 6766262d7e75..9851551ebbe0 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -15,7 +15,7 @@ * Yogesh Gaur <yogeshnarayan.gaur@nxp.com> * Suresh Gupta <suresh.gupta@nxp.com> * - * Based on the original fsl-quadspi.c spi-nor driver: + * Based on the original fsl-quadspi.c SPI NOR driver: * Author: Freescale Semiconductor, Inc. * */ diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 67f022b8c81d..299e9870cf58 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -90,7 +90,7 @@ static void fsl_spi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi->controller_state; - struct fsl_spi_reg *reg_base = mspi->reg_base; + struct fsl_spi_reg __iomem *reg_base = mspi->reg_base; __be32 __iomem *mode = ®_base->mode; unsigned long flags; @@ -291,7 +291,7 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, unsigned int len) { u32 word; - struct fsl_spi_reg *reg_base = mspi->reg_base; + struct fsl_spi_reg __iomem *reg_base = mspi->reg_base; mspi->count = len; @@ -309,7 +309,7 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, bool is_dma_mapped) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - struct fsl_spi_reg *reg_base; + struct fsl_spi_reg __iomem *reg_base; unsigned int len = t->len; u8 bits_per_word; int ret; @@ -440,7 +440,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master, static int fsl_spi_setup(struct spi_device *spi) { struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_spi_reg *reg_base; + struct fsl_spi_reg __iomem *reg_base; int retval; u32 hw_mode; struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); @@ -495,7 +495,7 @@ static void fsl_spi_cleanup(struct spi_device *spi) static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) { - struct fsl_spi_reg *reg_base = mspi->reg_base; + struct fsl_spi_reg __iomem *reg_base = mspi->reg_base; /* We need handle RX first */ if (events & SPIE_NE) { @@ -530,7 +530,7 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) struct mpc8xxx_spi *mspi = context_data; irqreturn_t ret = IRQ_NONE; u32 events; - struct fsl_spi_reg *reg_base = mspi->reg_base; + struct fsl_spi_reg __iomem *reg_base = mspi->reg_base; /* Get interrupt events(tx/rx) */ events = mpc8xxx_spi_read_reg(®_base->event); @@ -550,7 +550,7 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base; + struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base; u32 slvsel; u16 cs = spi->chip_select; @@ -568,7 +568,7 @@ static void fsl_spi_grlib_probe(struct device *dev) struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master = dev_get_drvdata(dev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); - struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base; + struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base; int mbits; u32 capabilities; @@ -594,7 +594,7 @@ static struct spi_master *fsl_spi_probe(struct device *dev, struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_spi_reg *reg_base; + struct fsl_spi_reg __iomem *reg_base; u32 regval; int ret = 0; diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index c3972424af71..1d96a7f32fda 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -51,7 +51,6 @@ /* M_CMD OP codes for SPI */ #define SPI_TX_ONLY 1 #define SPI_RX_ONLY 2 -#define SPI_FULL_DUPLEX 3 #define SPI_TX_RX 7 #define SPI_CS_ASSERT 8 #define SPI_CS_DEASSERT 9 @@ -63,13 +62,6 @@ #define TIMESTAMP_AFTER BIT(3) #define POST_CMD_DELAY BIT(4) -enum spi_m_cmd_opcode { - CMD_NONE, - CMD_XFER, - CMD_CS, - CMD_CANCEL, -}; - struct spi_geni_master { struct geni_se se; struct device *dev; @@ -81,11 +73,13 @@ struct spi_geni_master { unsigned int tx_rem_bytes; unsigned int rx_rem_bytes; const struct spi_transfer *cur_xfer; - struct completion xfer_done; + struct completion cs_done; + struct completion cancel_done; + struct completion abort_done; unsigned int oversampling; spinlock_t lock; - enum spi_m_cmd_opcode cur_mcmd; int irq; + bool cs_flag; }; static int get_spi_clk_cfg(unsigned int speed_hz, @@ -122,24 +116,26 @@ static void handle_fifo_timeout(struct spi_master *spi, struct spi_message *msg) { struct spi_geni_master *mas = spi_master_get_devdata(spi); - unsigned long time_left, flags; + unsigned long time_left; struct geni_se *se = &mas->se; - spin_lock_irqsave(&mas->lock, flags); - reinit_completion(&mas->xfer_done); - mas->cur_mcmd = CMD_CANCEL; - geni_se_cancel_m_cmd(se); + spin_lock_irq(&mas->lock); + reinit_completion(&mas->cancel_done); writel(0, se->base + SE_GENI_TX_WATERMARK_REG); - spin_unlock_irqrestore(&mas->lock, flags); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + mas->cur_xfer = NULL; + geni_se_cancel_m_cmd(se); + spin_unlock_irq(&mas->lock); + + time_left = wait_for_completion_timeout(&mas->cancel_done, HZ); if (time_left) return; - spin_lock_irqsave(&mas->lock, flags); - reinit_completion(&mas->xfer_done); + spin_lock_irq(&mas->lock); + reinit_completion(&mas->abort_done); geni_se_abort_m_cmd(se); - spin_unlock_irqrestore(&mas->lock, flags); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + spin_unlock_irq(&mas->lock); + + time_left = wait_for_completion_timeout(&mas->abort_done, HZ); if (!time_left) dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); } @@ -151,18 +147,24 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) struct geni_se *se = &mas->se; unsigned long time_left; - reinit_completion(&mas->xfer_done); - pm_runtime_get_sync(mas->dev); if (!(slv->mode & SPI_CS_HIGH)) set_flag = !set_flag; - mas->cur_mcmd = CMD_CS; + if (set_flag == mas->cs_flag) + return; + + mas->cs_flag = set_flag; + + pm_runtime_get_sync(mas->dev); + spin_lock_irq(&mas->lock); + reinit_completion(&mas->cs_done); if (set_flag) geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); else geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); + spin_unlock_irq(&mas->lock); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + time_left = wait_for_completion_timeout(&mas->cs_done, HZ); if (!time_left) handle_fifo_timeout(spi, NULL); @@ -283,7 +285,7 @@ static int spi_geni_init(struct spi_geni_master *mas) * Hardware programming guide suggests to configure * RX FIFO RFR level to fifo_depth-2. */ - geni_se_init(se, 0x0, mas->tx_fifo_depth - 2); + geni_se_init(se, mas->tx_fifo_depth / 2, mas->tx_fifo_depth - 2); /* Transmit an entire FIFO worth of data per IRQ */ mas->tx_wm = 1; ver = geni_se_get_qup_hw_version(se); @@ -307,6 +309,21 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, u32 spi_tx_cfg, len; struct geni_se *se = &mas->se; + /* + * Ensure that our interrupt handler isn't still running from some + * prior command before we start messing with the hardware behind + * its back. We don't need to _keep_ the lock here since we're only + * worried about racing with out interrupt handler. The SPI core + * already handles making sure that we're not trying to do two + * transfers at once or setting a chip select and doing a transfer + * concurrently. + * + * NOTE: we actually _can't_ hold the lock here because possibly we + * might call clk_set_rate() which needs to be able to sleep. + */ + spin_lock_irq(&mas->lock); + spin_unlock_irq(&mas->lock); + spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); if (xfer->bits_per_word != mas->cur_bits_per_word) { spi_setup_word_len(mas, mode, xfer->bits_per_word); @@ -340,12 +357,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, mas->tx_rem_bytes = 0; mas->rx_rem_bytes = 0; - if (xfer->tx_buf && xfer->rx_buf) - m_cmd = SPI_FULL_DUPLEX; - else if (xfer->tx_buf) - m_cmd = SPI_TX_ONLY; - else if (xfer->rx_buf) - m_cmd = SPI_RX_ONLY; spi_tx_cfg &= ~CS_TOGGLE; @@ -356,17 +367,24 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, len &= TRANS_LEN_MSK; mas->cur_xfer = xfer; - if (m_cmd & SPI_TX_ONLY) { + if (xfer->tx_buf) { + m_cmd |= SPI_TX_ONLY; mas->tx_rem_bytes = xfer->len; writel(len, se->base + SE_SPI_TX_TRANS_LEN); } - if (m_cmd & SPI_RX_ONLY) { + if (xfer->rx_buf) { + m_cmd |= SPI_RX_ONLY; writel(len, se->base + SE_SPI_RX_TRANS_LEN); mas->rx_rem_bytes = xfer->len; } writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); - mas->cur_mcmd = CMD_XFER; + + /* + * Lock around right before we start the transfer since our + * interrupt could come in at any time now. + */ + spin_lock_irq(&mas->lock); geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); /* @@ -376,6 +394,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, */ if (m_cmd & SPI_TX_ONLY) writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); + spin_unlock_irq(&mas->lock); } static int spi_geni_transfer_one(struct spi_master *spi, @@ -477,13 +496,17 @@ static irqreturn_t geni_spi_isr(int irq, void *data) struct spi_geni_master *mas = spi_master_get_devdata(spi); struct geni_se *se = &mas->se; u32 m_irq; - unsigned long flags; - if (mas->cur_mcmd == CMD_NONE) + m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); + if (!m_irq) return IRQ_NONE; - spin_lock_irqsave(&mas->lock, flags); - m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); + if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN | + M_RX_FIFO_RD_ERR_EN | M_RX_FIFO_WR_ERR_EN | + M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN)) + dev_warn(mas->dev, "Unexpected IRQ err status %#010x\n", m_irq); + + spin_lock(&mas->lock); if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) geni_spi_handle_rx(mas); @@ -492,39 +515,57 @@ static irqreturn_t geni_spi_isr(int irq, void *data) geni_spi_handle_tx(mas); if (m_irq & M_CMD_DONE_EN) { - if (mas->cur_mcmd == CMD_XFER) + if (mas->cur_xfer) { spi_finalize_current_transfer(spi); - else if (mas->cur_mcmd == CMD_CS) - complete(&mas->xfer_done); - mas->cur_mcmd = CMD_NONE; - /* - * If this happens, then a CMD_DONE came before all the Tx - * buffer bytes were sent out. This is unusual, log this - * condition and disable the WM interrupt to prevent the - * system from stalling due an interrupt storm. - * If this happens when all Rx bytes haven't been received, log - * the condition. - * The only known time this can happen is if bits_per_word != 8 - * and some registers that expect xfer lengths in num spi_words - * weren't written correctly. - */ - if (mas->tx_rem_bytes) { - writel(0, se->base + SE_GENI_TX_WATERMARK_REG); - dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", - mas->tx_rem_bytes, mas->cur_bits_per_word); + mas->cur_xfer = NULL; + /* + * If this happens, then a CMD_DONE came before all the + * Tx buffer bytes were sent out. This is unusual, log + * this condition and disable the WM interrupt to + * prevent the system from stalling due an interrupt + * storm. + * + * If this happens when all Rx bytes haven't been + * received, log the condition. The only known time + * this can happen is if bits_per_word != 8 and some + * registers that expect xfer lengths in num spi_words + * weren't written correctly. + */ + if (mas->tx_rem_bytes) { + writel(0, se->base + SE_GENI_TX_WATERMARK_REG); + dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", + mas->tx_rem_bytes, mas->cur_bits_per_word); + } + if (mas->rx_rem_bytes) + dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", + mas->rx_rem_bytes, mas->cur_bits_per_word); + } else { + complete(&mas->cs_done); } - if (mas->rx_rem_bytes) - dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", - mas->rx_rem_bytes, mas->cur_bits_per_word); } - if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) { - mas->cur_mcmd = CMD_NONE; - complete(&mas->xfer_done); - } + if (m_irq & M_CMD_CANCEL_EN) + complete(&mas->cancel_done); + if (m_irq & M_CMD_ABORT_EN) + complete(&mas->abort_done); + /* + * It's safe or a good idea to Ack all of our our interrupts at the + * end of the function. Specifically: + * - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and + * clearing Acks. Clearing at the end relies on nobody else having + * started a new transfer yet or else we could be clearing _their_ + * done bit, but everyone grabs the spinlock before starting a new + * transfer. + * - M_RX_FIFO_WATERMARK_EN / M_TX_FIFO_WATERMARK_EN: These appear + * to be "latched level" interrupts so it's important to clear them + * _after_ you've handled the condition and always safe to do so + * since they'll re-assert if they're still happening. + */ writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); - spin_unlock_irqrestore(&mas->lock, flags); + + spin_unlock(&mas->lock); + return IRQ_HANDLED; } @@ -574,8 +615,12 @@ static int spi_geni_probe(struct platform_device *pdev) spi->handle_err = handle_fifo_timeout; spi->set_cs = spi_geni_set_cs; - init_completion(&mas->xfer_done); + init_completion(&mas->cs_done); + init_completion(&mas->cancel_done); + init_completion(&mas->abort_done); spin_lock_init(&mas->lock); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 250); pm_runtime_enable(dev); ret = spi_geni_init(mas); diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 8543f5ed1099..b068537375d6 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -9,7 +9,6 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/dmaengine.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> @@ -102,10 +101,6 @@ struct img_spfi { bool rx_dma_busy; }; -struct img_spfi_device_data { - bool gpio_requested; -}; - static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) { return readl(spfi->regs + reg); @@ -442,54 +437,6 @@ static int img_spfi_unprepare(struct spi_master *master, return 0; } -static int img_spfi_setup(struct spi_device *spi) -{ - int ret = -EINVAL; - struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); - - if (!spfi_data) { - spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL); - if (!spfi_data) - return -ENOMEM; - spfi_data->gpio_requested = false; - spi_set_ctldata(spi, spfi_data); - } - if (!spfi_data->gpio_requested) { - ret = gpio_request_one(spi->cs_gpio, - (spi->mode & SPI_CS_HIGH) ? - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, - dev_name(&spi->dev)); - if (ret) - dev_err(&spi->dev, "can't request chipselect gpio %d\n", - spi->cs_gpio); - else - spfi_data->gpio_requested = true; - } else { - if (gpio_is_valid(spi->cs_gpio)) { - int mode = ((spi->mode & SPI_CS_HIGH) ? - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); - - ret = gpio_direction_output(spi->cs_gpio, mode); - if (ret) - dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", - spi->cs_gpio, ret); - } - } - return ret; -} - -static void img_spfi_cleanup(struct spi_device *spi) -{ - struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); - - if (spfi_data) { - if (spfi_data->gpio_requested) - gpio_free(spi->cs_gpio); - kfree(spfi_data); - spi_set_ctldata(spi, NULL); - } -} - static void img_spfi_config(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { @@ -659,12 +606,11 @@ static int img_spfi_probe(struct platform_device *pdev) master->max_speed_hz = max_speed_hz; } - master->setup = img_spfi_setup; - master->cleanup = img_spfi_cleanup; master->transfer_one = img_spfi_transfer_one; master->prepare_message = img_spfi_prepare; master->unprepare_message = img_spfi_unprepare; master->handle_err = img_spfi_handle_err; + master->use_gpio_descriptors = true; spfi->tx_ch = dma_request_chan(spfi->dev, "tx"); if (IS_ERR(spfi->tx_ch)) { diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index b7a85e3fe1c1..38a5f1304cec 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -8,23 +8,23 @@ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/types.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> +#include <linux/property.h> #include <linux/platform_data/dma-imx.h> -#include <linux/platform_data/spi-imx.h> #define DRIVER_NAME "spi_imx" @@ -32,6 +32,8 @@ static bool use_dma = true; module_param(use_dma, bool, 0644); MODULE_PARM_DESC(use_dma, "Enable usage of DMA when available (default)"); +#define MXC_RPM_TIMEOUT 2000 /* 2000ms */ + #define MXC_CSPIRXDATA 0x00 #define MXC_CSPITXDATA 0x04 #define MXC_CSPICTRL 0x08 @@ -224,7 +226,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, { struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - if (!use_dma) + if (!use_dma || master->fallback) return false; if (!master->dma_rx) @@ -723,7 +725,7 @@ static int mx31_prepare_transfer(struct spi_imx_data *spi_imx, reg |= MX31_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX31_CSPICTRL_SSPOL; - if (!gpio_is_valid(spi->cs_gpio)) + if (!spi->cs_gpiod) reg |= (spi->chip_select) << (is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : MX31_CSPICTRL_CS_SHIFT); @@ -824,7 +826,7 @@ static int mx21_prepare_transfer(struct spi_imx_data *spi_imx, reg |= MX21_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX21_CSPICTRL_SSPOL; - if (!gpio_is_valid(spi->cs_gpio)) + if (!spi->cs_gpiod) reg |= spi->chip_select << MX21_CSPICTRL_CS_SHIFT; writel(reg, spi_imx->base + MXC_CSPICTRL); @@ -1056,20 +1058,6 @@ static const struct of_device_id spi_imx_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, spi_imx_dt_ids); -static void spi_imx_chipselect(struct spi_device *spi, int is_active) -{ - int active = is_active != BITBANG_CS_INACTIVE; - int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH); - - if (spi->mode & SPI_NO_CS) - return; - - if (!gpio_is_valid(spi->cs_gpio)) - return; - - gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active); -} - static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits) { u32 ctrl; @@ -1364,11 +1352,12 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ret = spi_imx_dma_configure(master); if (ret) - return ret; + goto dma_failure_no_start; if (!spi_imx->devtype_data->setup_wml) { dev_err(spi_imx->dev, "No setup_wml()?\n"); - return -EINVAL; + ret = -EINVAL; + goto dma_failure_no_start; } spi_imx->devtype_data->setup_wml(spi_imx); @@ -1379,8 +1368,10 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, desc_rx = dmaengine_prep_slave_sg(master->dma_rx, rx->sgl, rx->nents, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_rx) - return -EINVAL; + if (!desc_rx) { + ret = -EINVAL; + goto dma_failure_no_start; + } desc_rx->callback = spi_imx_dma_rx_callback; desc_rx->callback_param = (void *)spi_imx; @@ -1425,6 +1416,10 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, } return transfer->len; +/* fallback to pio */ +dma_failure_no_start: + transfer->error |= SPI_TRANS_FAIL_NO_START; + return ret; } static int spi_imx_pio_transfer(struct spi_device *spi, @@ -1507,7 +1502,6 @@ static int spi_imx_transfer(struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); - int ret; /* flush rxfifo before transfer */ while (spi_imx->devtype_data->rx_available(spi_imx)) @@ -1516,21 +1510,8 @@ static int spi_imx_transfer(struct spi_device *spi, if (spi_imx->slave_mode) return spi_imx_pio_transfer_slave(spi, transfer); - /* - * fallback PIO mode if dma setup error happen, for example sdma - * firmware may not be updated as ERR009165 required. - */ - if (spi_imx->usedma) { - ret = spi_imx_dma_transfer(spi_imx, transfer); - if (ret != -EINVAL) - return ret; - - spi_imx->devtype_data->disable_dma(spi_imx); - - spi_imx->usedma = false; - spi_imx->dynamic_burst = spi_imx->devtype_data->dynamic_burst; - dev_dbg(&spi->dev, "Fallback to PIO mode\n"); - } + if (spi_imx->usedma) + return spi_imx_dma_transfer(spi_imx, transfer); return spi_imx_pio_transfer(spi, transfer); } @@ -1540,15 +1521,6 @@ static int spi_imx_setup(struct spi_device *spi) dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); - if (spi->mode & SPI_NO_CS) - return 0; - - if (gpio_is_valid(spi->cs_gpio)) - gpio_direction_output(spi->cs_gpio, - spi->mode & SPI_CS_HIGH ? 0 : 1); - - spi_imx_chipselect(spi, BITBANG_CS_INACTIVE); - return 0; } @@ -1562,20 +1534,16 @@ spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg) struct spi_imx_data *spi_imx = spi_master_get_devdata(master); int ret; - ret = clk_enable(spi_imx->clk_per); - if (ret) - return ret; - - ret = clk_enable(spi_imx->clk_ipg); - if (ret) { - clk_disable(spi_imx->clk_per); + ret = pm_runtime_get_sync(spi_imx->dev); + if (ret < 0) { + dev_err(spi_imx->dev, "failed to enable clock\n"); return ret; } ret = spi_imx->devtype_data->prepare_message(spi_imx, msg); if (ret) { - clk_disable(spi_imx->clk_ipg); - clk_disable(spi_imx->clk_per); + pm_runtime_mark_last_busy(spi_imx->dev); + pm_runtime_put_autosuspend(spi_imx->dev); } return ret; @@ -1586,8 +1554,8 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg) { struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - clk_disable(spi_imx->clk_ipg); - clk_disable(spi_imx->clk_per); + pm_runtime_mark_last_busy(spi_imx->dev); + pm_runtime_put_autosuspend(spi_imx->dev); return 0; } @@ -1606,20 +1574,14 @@ static int spi_imx_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(spi_imx_dt_ids, &pdev->dev); - struct spi_imx_master *mxc_platform_info = - dev_get_platdata(&pdev->dev); struct spi_master *master; struct spi_imx_data *spi_imx; struct resource *res; - int i, ret, irq, spi_drctl; + int ret, irq, spi_drctl; const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data : (struct spi_imx_devtype_data *)pdev->id_entry->driver_data; bool slave_mode; - - if (!np && !mxc_platform_info) { - dev_err(&pdev->dev, "can't get the platform data\n"); - return -EINVAL; - } + u32 val; slave_mode = devtype_data->has_slavemode && of_property_read_bool(np, "spi-slave"); @@ -1642,6 +1604,7 @@ static int spi_imx_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->bus_num = np ? -1 : pdev->id; + master->use_gpio_descriptors = true; spi_imx = spi_master_get_devdata(master); spi_imx->bitbang.master = master; @@ -1650,28 +1613,17 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->devtype_data = devtype_data; - /* Get number of chip selects, either platform data or OF */ - if (mxc_platform_info) { - master->num_chipselect = mxc_platform_info->num_chipselect; - if (mxc_platform_info->chipselect) { - master->cs_gpios = devm_kcalloc(&master->dev, - master->num_chipselect, sizeof(int), - GFP_KERNEL); - if (!master->cs_gpios) - return -ENOMEM; - - for (i = 0; i < master->num_chipselect; i++) - master->cs_gpios[i] = mxc_platform_info->chipselect[i]; - } - } else { - u32 num_cs; - - if (!of_property_read_u32(np, "num-cs", &num_cs)) - master->num_chipselect = num_cs; - /* If not preset, default value of 1 is used */ - } + /* + * Get number of chip selects from device properties. This can be + * coming from device tree or boardfiles, if it is not defined, + * a default value of 3 chip selects will be used, as all the legacy + * board files have <= 3 chip selects. + */ + if (!device_property_read_u32(&pdev->dev, "num-cs", &val)) + master->num_chipselect = val; + else + master->num_chipselect = 3; - spi_imx->bitbang.chipselect = spi_imx_chipselect; spi_imx->bitbang.setup_transfer = spi_imx_setupxfer; spi_imx->bitbang.txrx_bufs = spi_imx_transfer; spi_imx->bitbang.master->setup = spi_imx_setup; @@ -1722,13 +1674,15 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_master_put; } - ret = clk_prepare_enable(spi_imx->clk_per); - if (ret) - goto out_master_put; + pm_runtime_enable(spi_imx->dev); + pm_runtime_set_autosuspend_delay(spi_imx->dev, MXC_RPM_TIMEOUT); + pm_runtime_use_autosuspend(spi_imx->dev); - ret = clk_prepare_enable(spi_imx->clk_ipg); - if (ret) - goto out_put_per; + ret = pm_runtime_get_sync(spi_imx->dev); + if (ret < 0) { + dev_err(spi_imx->dev, "failed to enable clock\n"); + goto out_runtime_pm_put; + } spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per); /* @@ -1738,7 +1692,7 @@ static int spi_imx_probe(struct platform_device *pdev) if (spi_imx->devtype_data->has_dmamode) { ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master); if (ret == -EPROBE_DEFER) - goto out_clk_put; + goto out_runtime_pm_put; if (ret < 0) dev_err(&pdev->dev, "dma setup error %d, use pio\n", @@ -1753,38 +1707,20 @@ static int spi_imx_probe(struct platform_device *pdev) ret = spi_bitbang_start(&spi_imx->bitbang); if (ret) { dev_err(&pdev->dev, "bitbang start failed with %d\n", ret); - goto out_clk_put; - } - - /* Request GPIO CS lines, if any */ - if (!spi_imx->slave_mode && master->cs_gpios) { - for (i = 0; i < master->num_chipselect; i++) { - if (!gpio_is_valid(master->cs_gpios[i])) - continue; - - ret = devm_gpio_request(&pdev->dev, - master->cs_gpios[i], - DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, "Can't get CS GPIO %i\n", - master->cs_gpios[i]); - goto out_spi_bitbang; - } - } + goto out_runtime_pm_put; } dev_info(&pdev->dev, "probed\n"); - clk_disable(spi_imx->clk_ipg); - clk_disable(spi_imx->clk_per); + pm_runtime_mark_last_busy(spi_imx->dev); + pm_runtime_put_autosuspend(spi_imx->dev); + return ret; -out_spi_bitbang: - spi_bitbang_stop(&spi_imx->bitbang); -out_clk_put: - clk_disable_unprepare(spi_imx->clk_ipg); -out_put_per: - clk_disable_unprepare(spi_imx->clk_per); +out_runtime_pm_put: + pm_runtime_dont_use_autosuspend(spi_imx->dev); + pm_runtime_put_sync(spi_imx->dev); + pm_runtime_disable(spi_imx->dev); out_master_put: spi_master_put(master); @@ -1799,30 +1735,82 @@ static int spi_imx_remove(struct platform_device *pdev) spi_bitbang_stop(&spi_imx->bitbang); - ret = clk_enable(spi_imx->clk_per); + ret = pm_runtime_get_sync(spi_imx->dev); + if (ret < 0) { + dev_err(spi_imx->dev, "failed to enable clock\n"); + return ret; + } + + writel(0, spi_imx->base + MXC_CSPICTRL); + + pm_runtime_dont_use_autosuspend(spi_imx->dev); + pm_runtime_put_sync(spi_imx->dev); + pm_runtime_disable(spi_imx->dev); + + spi_imx_sdma_exit(spi_imx); + spi_master_put(master); + + return 0; +} + +static int __maybe_unused spi_imx_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_imx_data *spi_imx; + int ret; + + spi_imx = spi_master_get_devdata(master); + + ret = clk_prepare_enable(spi_imx->clk_per); if (ret) return ret; - ret = clk_enable(spi_imx->clk_ipg); + ret = clk_prepare_enable(spi_imx->clk_ipg); if (ret) { - clk_disable(spi_imx->clk_per); + clk_disable_unprepare(spi_imx->clk_per); return ret; } - writel(0, spi_imx->base + MXC_CSPICTRL); - clk_disable_unprepare(spi_imx->clk_ipg); + return 0; +} + +static int __maybe_unused spi_imx_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_imx_data *spi_imx; + + spi_imx = spi_master_get_devdata(master); + clk_disable_unprepare(spi_imx->clk_per); - spi_imx_sdma_exit(spi_imx); - spi_master_put(master); + clk_disable_unprepare(spi_imx->clk_ipg); + + return 0; +} + +static int __maybe_unused spi_imx_suspend(struct device *dev) +{ + pinctrl_pm_select_sleep_state(dev); + return 0; +} +static int __maybe_unused spi_imx_resume(struct device *dev) +{ + pinctrl_pm_select_default_state(dev); return 0; } +static const struct dev_pm_ops imx_spi_pm = { + SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend, + spi_imx_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume) +}; + static struct platform_driver spi_imx_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = spi_imx_dt_ids, - }, + .pm = &imx_spi_pm, + }, .id_table = spi_imx_devtype, .probe = spi_imx_probe, .remove = spi_imx_remove, diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index 1fd7ee53d451..dccef1dcea32 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -15,7 +15,6 @@ #include <linux/completion.h> #include <linux/spinlock.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/pm_runtime.h> #include <linux/spi/spi.h> @@ -50,8 +49,6 @@ #define LTQ_SPI_RXCNT 0x84 #define LTQ_SPI_DMACON 0xec #define LTQ_SPI_IRNEN 0xf4 -#define LTQ_SPI_IRNICR 0xf8 -#define LTQ_SPI_IRNCR 0xfc #define LTQ_SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */ #define LTQ_SPI_CLC_SMC_M (0xFF << LTQ_SPI_CLC_SMC_S) @@ -61,9 +58,7 @@ #define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ #define LTQ_SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */ -#define LTQ_SPI_ID_TXFS_M (0x3F << LTQ_SPI_ID_TXFS_S) #define LTQ_SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */ -#define LTQ_SPI_ID_RXFS_M (0x3F << LTQ_SPI_ID_RXFS_S) #define LTQ_SPI_ID_MOD_S 8 /* Module ID */ #define LTQ_SPI_ID_MOD_M (0xff << LTQ_SPI_ID_MOD_S) #define LTQ_SPI_ID_CFG_S 5 /* DMA interface support */ @@ -126,19 +121,15 @@ LTQ_SPI_WHBSTATE_CLRTUE) #define LTQ_SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */ -#define LTQ_SPI_RXFCON_RXFITL_M (0x3F << LTQ_SPI_RXFCON_RXFITL_S) #define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ #define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ #define LTQ_SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */ -#define LTQ_SPI_TXFCON_TXFITL_M (0x3F << LTQ_SPI_TXFCON_TXFITL_S) #define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ #define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ #define LTQ_SPI_FSTAT_RXFFL_S 0 -#define LTQ_SPI_FSTAT_RXFFL_M (0x3f << LTQ_SPI_FSTAT_RXFFL_S) #define LTQ_SPI_FSTAT_TXFFL_S 8 -#define LTQ_SPI_FSTAT_TXFFL_M (0x3f << LTQ_SPI_FSTAT_TXFFL_S) #define LTQ_SPI_GPOCON_ISCSBN_S 8 #define LTQ_SPI_GPOCON_INVOUTN_S 0 @@ -158,9 +149,16 @@ #define LTQ_SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */ #define LTQ_SPI_IRNEN_ALL 0x1F +struct lantiq_ssc_spi; + struct lantiq_ssc_hwcfg { - unsigned int irnen_r; - unsigned int irnen_t; + int (*cfg_irq)(struct platform_device *pdev, struct lantiq_ssc_spi *spi); + unsigned int irnen_r; + unsigned int irnen_t; + unsigned int irncr; + unsigned int irnicr; + bool irq_ack; + u32 fifo_size_mask; }; struct lantiq_ssc_spi { @@ -184,6 +182,7 @@ struct lantiq_ssc_spi { unsigned int tx_fifo_size; unsigned int rx_fifo_size; unsigned int base_cs; + unsigned int fdx_tx_level; }; static u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg) @@ -209,16 +208,18 @@ static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr, static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi) { + const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT); - return (fstat & LTQ_SPI_FSTAT_TXFFL_M) >> LTQ_SPI_FSTAT_TXFFL_S; + return (fstat >> LTQ_SPI_FSTAT_TXFFL_S) & hwcfg->fifo_size_mask; } static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi) { + const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT); - return fstat & LTQ_SPI_FSTAT_RXFFL_M; + return (fstat >> LTQ_SPI_FSTAT_RXFFL_S) & hwcfg->fifo_size_mask; } static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi) @@ -391,7 +392,7 @@ static int lantiq_ssc_setup(struct spi_device *spidev) u32 gpocon; /* GPIOs are used for CS */ - if (gpio_is_valid(spidev->cs_gpio)) + if (spidev->cs_gpiod) return 0; dev_dbg(spi->dev, "using internal chipselect %u\n", cs); @@ -481,6 +482,7 @@ static void tx_fifo_write(struct lantiq_ssc_spi *spi) u32 data; unsigned int tx_free = tx_fifo_free(spi); + spi->fdx_tx_level = 0; while (spi->tx_todo && tx_free) { switch (spi->bits_per_word) { case 2 ... 8: @@ -509,6 +511,7 @@ static void tx_fifo_write(struct lantiq_ssc_spi *spi) lantiq_ssc_writel(spi, data, LTQ_SPI_TB); tx_free--; + spi->fdx_tx_level++; } } @@ -520,6 +523,13 @@ static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi) u32 data; unsigned int rx_fill = rx_fifo_level(spi); + /* + * Wait until all expected data to be shifted in. + * Otherwise, rx overrun may occur. + */ + while (rx_fill != spi->fdx_tx_level) + rx_fill = rx_fifo_level(spi); + while (rx_fill) { data = lantiq_ssc_readl(spi, LTQ_SPI_RB); @@ -613,6 +623,13 @@ static void rx_request(struct lantiq_ssc_spi *spi) static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data) { struct lantiq_ssc_spi *spi = data; + const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; + u32 val = lantiq_ssc_readl(spi, hwcfg->irncr); + unsigned long flags; + + spin_lock_irqsave(&spi->lock, flags); + if (hwcfg->irq_ack) + lantiq_ssc_writel(spi, val, hwcfg->irncr); if (spi->tx) { if (spi->rx && spi->rx_todo) @@ -635,10 +652,12 @@ static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data) } } + spin_unlock_irqrestore(&spi->lock, flags); return IRQ_HANDLED; completed: queue_work(spi->wq, &spi->work); + spin_unlock_irqrestore(&spi->lock, flags); return IRQ_HANDLED; } @@ -646,11 +665,18 @@ completed: static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data) { struct lantiq_ssc_spi *spi = data; + const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT); + u32 val = lantiq_ssc_readl(spi, hwcfg->irncr); + unsigned long flags; if (!(stat & LTQ_SPI_STAT_ERRORS)) return IRQ_NONE; + spin_lock_irqsave(&spi->lock, flags); + if (hwcfg->irq_ack) + lantiq_ssc_writel(spi, val, hwcfg->irncr); + if (stat & LTQ_SPI_STAT_RUE) dev_err(spi->dev, "receive underflow error\n"); if (stat & LTQ_SPI_STAT_TUE) @@ -671,6 +697,25 @@ static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data) if (spi->master->cur_msg) spi->master->cur_msg->status = -EIO; queue_work(spi->wq, &spi->work); + spin_unlock_irqrestore(&spi->lock, flags); + + return IRQ_HANDLED; +} + +static irqreturn_t intel_lgm_ssc_isr(int irq, void *data) +{ + struct lantiq_ssc_spi *spi = data; + const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; + u32 val = lantiq_ssc_readl(spi, hwcfg->irncr); + + if (!(val & LTQ_SPI_IRNEN_ALL)) + return IRQ_NONE; + + if (val & LTQ_SPI_IRNEN_E) + return lantiq_ssc_err_interrupt(irq, data); + + if ((val & hwcfg->irnen_t) || (val & hwcfg->irnen_r)) + return lantiq_ssc_xmit_interrupt(irq, data); return IRQ_HANDLED; } @@ -775,20 +820,84 @@ static int lantiq_ssc_transfer_one(struct spi_master *master, return transfer_start(spi, spidev, t); } +static int intel_lgm_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi) +{ + int irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + return devm_request_irq(&pdev->dev, irq, intel_lgm_ssc_isr, 0, "spi", spi); +} + +static int lantiq_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi) +{ + int irq, err; + + irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME); + if (irq < 0) + return irq; + + err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt, + 0, LTQ_SPI_RX_IRQ_NAME, spi); + if (err) + return err; + + irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME); + if (irq < 0) + return irq; + + err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt, + 0, LTQ_SPI_TX_IRQ_NAME, spi); + + if (err) + return err; + + irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME); + if (irq < 0) + return irq; + + err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_err_interrupt, + 0, LTQ_SPI_ERR_IRQ_NAME, spi); + return err; +} + static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = { - .irnen_r = LTQ_SPI_IRNEN_R_XWAY, - .irnen_t = LTQ_SPI_IRNEN_T_XWAY, + .cfg_irq = lantiq_cfg_irq, + .irnen_r = LTQ_SPI_IRNEN_R_XWAY, + .irnen_t = LTQ_SPI_IRNEN_T_XWAY, + .irnicr = 0xF8, + .irncr = 0xFC, + .fifo_size_mask = GENMASK(5, 0), + .irq_ack = false, }; static const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = { - .irnen_r = LTQ_SPI_IRNEN_R_XRX, - .irnen_t = LTQ_SPI_IRNEN_T_XRX, + .cfg_irq = lantiq_cfg_irq, + .irnen_r = LTQ_SPI_IRNEN_R_XRX, + .irnen_t = LTQ_SPI_IRNEN_T_XRX, + .irnicr = 0xF8, + .irncr = 0xFC, + .fifo_size_mask = GENMASK(5, 0), + .irq_ack = false, +}; + +static const struct lantiq_ssc_hwcfg intel_ssc_lgm = { + .cfg_irq = intel_lgm_cfg_irq, + .irnen_r = LTQ_SPI_IRNEN_R_XRX, + .irnen_t = LTQ_SPI_IRNEN_T_XRX, + .irnicr = 0xFC, + .irncr = 0xF8, + .fifo_size_mask = GENMASK(7, 0), + .irq_ack = true, }; static const struct of_device_id lantiq_ssc_match[] = { { .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, }, { .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, }, { .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, }, + { .compatible = "intel,lgm-spi", .data = &intel_ssc_lgm, }, {}, }; MODULE_DEVICE_TABLE(of, lantiq_ssc_match); @@ -800,9 +909,9 @@ static int lantiq_ssc_probe(struct platform_device *pdev) struct lantiq_ssc_spi *spi; const struct lantiq_ssc_hwcfg *hwcfg; const struct of_device_id *match; - int err, rx_irq, tx_irq, err_irq; u32 id, supports_dma, revision; unsigned int num_cs; + int err; match = of_match_device(lantiq_ssc_match, dev); if (!match) { @@ -811,18 +920,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev) } hwcfg = match->data; - rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME); - if (rx_irq < 0) - return -ENXIO; - - tx_irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME); - if (tx_irq < 0) - return -ENXIO; - - err_irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME); - if (err_irq < 0) - return -ENXIO; - master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi)); if (!master) return -ENOMEM; @@ -838,18 +935,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev) goto err_master_put; } - err = devm_request_irq(dev, rx_irq, lantiq_ssc_xmit_interrupt, - 0, LTQ_SPI_RX_IRQ_NAME, spi); - if (err) - goto err_master_put; - - err = devm_request_irq(dev, tx_irq, lantiq_ssc_xmit_interrupt, - 0, LTQ_SPI_TX_IRQ_NAME, spi); - if (err) - goto err_master_put; - - err = devm_request_irq(dev, err_irq, lantiq_ssc_err_interrupt, - 0, LTQ_SPI_ERR_IRQ_NAME, spi); + err = hwcfg->cfg_irq(pdev, spi); if (err) goto err_master_put; @@ -888,6 +974,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->num_chipselect = num_cs; + master->use_gpio_descriptors = true; master->setup = lantiq_ssc_setup; master->set_cs = lantiq_ssc_set_cs; master->handle_err = lantiq_ssc_handle_err; @@ -907,8 +994,8 @@ static int lantiq_ssc_probe(struct platform_device *pdev) INIT_WORK(&spi->work, lantiq_ssc_bussy_work); id = lantiq_ssc_readl(spi, LTQ_SPI_ID); - spi->tx_fifo_size = (id & LTQ_SPI_ID_TXFS_M) >> LTQ_SPI_ID_TXFS_S; - spi->rx_fifo_size = (id & LTQ_SPI_ID_RXFS_M) >> LTQ_SPI_ID_RXFS_S; + spi->tx_fifo_size = (id >> LTQ_SPI_ID_TXFS_S) & hwcfg->fifo_size_mask; + spi->rx_fifo_size = (id >> LTQ_SPI_ID_RXFS_S) & hwcfg->fifo_size_mask; supports_dma = (id & LTQ_SPI_ID_CFG_M) >> LTQ_SPI_ID_CFG_S; revision = id & LTQ_SPI_ID_REV_M; diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index b6d79cd156fb..9522d1b5786d 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -885,10 +885,10 @@ static int spi_test_run_iter(struct spi_device *spi, /** * spi_test_execute_msg - default implementation to run a test * - * spi: @spi_device on which to run the @spi_message - * test: the test to execute, which already contains @msg - * tx: the tx buffer allocated for the test sequence - * rx: the rx buffer allocated for the test sequence + * @spi: @spi_device on which to run the @spi_message + * @test: the test to execute, which already contains @msg + * @tx: the tx buffer allocated for the test sequence + * @rx: the rx buffer allocated for the test sequence * * Returns: error code of spi_sync as well as basic error checking */ @@ -957,10 +957,10 @@ EXPORT_SYMBOL_GPL(spi_test_execute_msg); * including all the relevant iterations on: * length and buffer alignment * - * spi: the spi_device to send the messages to - * test: the test which we need to execute - * tx: the tx buffer allocated for the test sequence - * rx: the rx buffer allocated for the test sequence + * @spi: the spi_device to send the messages to + * @test: the test which we need to execute + * @tx: the tx buffer allocated for the test sequence + * @rx: the rx buffer allocated for the test sequence * * Returns: status code of spi_sync or other failures */ diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 9a86cc27fcc0..ef53290b7d24 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -156,6 +156,12 @@ bool spi_mem_default_supports_op(struct spi_mem *mem, op->data.dir == SPI_MEM_DATA_OUT)) return false; + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + return false; + + if (op->cmd.nbytes != 1) + return false; + return true; } EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); @@ -170,7 +176,7 @@ static bool spi_mem_buswidth_is_valid(u8 buswidth) static int spi_mem_check_op(const struct spi_mem_op *op) { - if (!op->cmd.buswidth) + if (!op->cmd.buswidth || !op->cmd.nbytes) return -EINVAL; if ((op->addr.nbytes && !op->addr.buswidth) || @@ -306,8 +312,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) return ret; } - tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + - op->dummy.nbytes; + tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; /* * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so @@ -322,7 +327,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) tmpbuf[0] = op->cmd.opcode; xfers[xferpos].tx_buf = tmpbuf; - xfers[xferpos].len = sizeof(op->cmd.opcode); + xfers[xferpos].len = op->cmd.nbytes; xfers[xferpos].tx_nbits = op->cmd.buswidth; spi_message_add_tail(&xfers[xferpos], &msg); xferpos++; @@ -424,8 +429,7 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) return ctlr->mem_ops->adjust_op_size(mem, op); if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) { - len = sizeof(op->cmd.opcode) + op->addr.nbytes + - op->dummy.nbytes; + len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; if (len > spi_max_transfer_size(mem->spi)) return -EINVAL; diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 77f7d0e0e46a..ecba6b4a5d85 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -362,8 +362,6 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc) { - u32 data; - if (spicc->data->has_oen) writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, SPICC_ENH_MAIN_CLK_AO, @@ -373,7 +371,7 @@ static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc) spicc->base + SPICC_TESTREG); while (meson_spicc_rxready(spicc)) - data = readl_relaxed(spicc->base + SPICC_RXDATA); + readl_relaxed(spicc->base + SPICC_RXDATA); if (spicc->data->has_oen) writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0, diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index c7b039980291..8eca6f24cb79 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -70,7 +70,7 @@ * @master: the SPI master * @regmap: regmap for device registers * @clk: input clock of the built-in baud rate generator - * @device: the device structure + * @dev: the device structure */ struct meson_spifc { struct spi_master *master; diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index a556795caeef..5d643051bf3d 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -171,6 +171,9 @@ static const struct of_device_id mtk_spi_of_match[] = { { .compatible = "mediatek,mt8183-spi", .data = (void *)&mt8183_compat, }, + { .compatible = "mediatek,mt8192-spi", + .data = (void *)&mt6765_compat, + }, {} }; MODULE_DEVICE_TABLE(of, mtk_spi_of_match); diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 7bc302b50396..b08d8e9a8ee9 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -195,7 +195,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) } } - len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes - + len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes - op->dummy.nbytes; if (op->data.nbytes > len) op->data.nbytes = len; @@ -211,6 +211,12 @@ static bool mtk_nor_supports_op(struct spi_mem *mem, if (op->cmd.buswidth != 1) return false; + /* DTR ops not supported. */ + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + return false; + if (op->cmd.nbytes != 1) + return false; + if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) { if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op)) return true; @@ -219,7 +225,7 @@ static bool mtk_nor_supports_op(struct spi_mem *mem, (op->dummy.buswidth == 0) && (op->data.buswidth == 1); } - len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; + len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; if ((len > MTK_NOR_PRG_MAX_SIZE) || ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE))) return false; diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 69491f3a515d..8c630acb0110 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -356,6 +356,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, int nio = 1, i, ret; u32 ss_ctrl; u8 addr[8]; + u8 opcode = op->cmd.opcode; ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz); if (ret) @@ -393,7 +394,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT, mxic->regs + HC_CFG); - ret = mxic_spi_data_xfer(mxic, &op->cmd.opcode, NULL, 1); + ret = mxic_spi_data_xfer(mxic, &opcode, NULL, 1); if (ret) goto out; diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index d25ee32862e0..9468e71f03ad 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Nuvoton Technology corporation. +#include <linux/bits.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/device.h> @@ -177,7 +178,6 @@ enum { #define MAP_SIZE_16MB 0x1000000 #define MAP_SIZE_8MB 0x800000 -#define NUM_BITS_IN_BYTE 8 #define FIU_DRD_MAX_DUMMY_NUMBER 3 #define NPCM_MAX_CHIP_NUM 4 #define CHUNK_SIZE 16 @@ -252,8 +252,8 @@ static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu, fiu->drd_op.addr.buswidth = op->addr.buswidth; regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, NPCM_FIU_DRD_CFG_DBW, - ((op->dummy.nbytes * ilog2(op->addr.buswidth)) - / NUM_BITS_IN_BYTE) << NPCM_FIU_DRD_DBW_SHIFT); + ((op->dummy.nbytes * ilog2(op->addr.buswidth)) / BITS_PER_BYTE) + << NPCM_FIU_DRD_DBW_SHIFT); fiu->drd_op.dummy.nbytes = op->dummy.nbytes; regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode); diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index 87cd0233c60b..56d10c4511db 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -10,8 +10,6 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> #include <linux/reset.h> #include <asm/unaligned.h> @@ -344,16 +342,9 @@ static int npcm_pspi_probe(struct platform_device *pdev) struct npcm_pspi *priv; struct spi_master *master; unsigned long clk_hz; - struct device_node *np = pdev->dev.of_node; - int num_cs, i; - int csgpio; int irq; int ret; - num_cs = of_gpio_named_count(np, "cs-gpios"); - if (num_cs < 0) - return num_cs; - master = spi_alloc_master(&pdev->dev, sizeof(*priv)); if (!master) return -ENOMEM; @@ -418,24 +409,7 @@ static int npcm_pspi_probe(struct platform_device *pdev) npcm_pspi_prepare_transfer_hardware; master->unprepare_transfer_hardware = npcm_pspi_unprepare_transfer_hardware; - master->num_chipselect = num_cs; - - for (i = 0; i < num_cs; i++) { - csgpio = of_get_named_gpio(np, "cs-gpios", i); - if (csgpio < 0) { - dev_err(&pdev->dev, "failed to get csgpio#%u\n", i); - goto out_disable_clk; - } - dev_dbg(&pdev->dev, "csgpio#%u = %d\n", i, csgpio); - ret = devm_gpio_request_one(&pdev->dev, csgpio, - GPIOF_OUT_INIT_HIGH, DRIVER_NAME); - if (ret < 0) { - dev_err(&pdev->dev, - "failed to configure csgpio#%u %d\n" - , i, csgpio); - goto out_disable_clk; - } - } + master->use_gpio_descriptors = true; /* set to default clock rate */ npcm_pspi_set_baudrate(priv, NPCM_PSPI_DEFAULT_CLK); diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 9df7c5979c29..f3843f0ff260 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -2,7 +2,7 @@ /* * OpenCores tiny SPI master driver * - * http://opencores.org/project,tiny_spi + * https://opencores.org/project,tiny_spi * * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw> * diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 5c704ba6d8ea..36a4922a134a 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -19,7 +19,6 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/slab.h> #include <linux/spi/spi.h> diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index ce8dbdbce312..71402f71ddd8 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -443,7 +443,7 @@ static void uwire_cleanup(struct spi_device *spi) static void uwire_off(struct uwire_spi *uwire) { uwire_write_reg(UWIRE_SR3, 0); - clk_disable(uwire->ck); + clk_disable_unprepare(uwire->ck); spi_master_put(uwire->bitbang.master); } @@ -475,7 +475,7 @@ static int uwire_probe(struct platform_device *pdev) spi_master_put(master); return status; } - clk_enable(uwire->ck); + clk_prepare_enable(uwire->ck); if (cpu_is_omap7xx()) uwire_idx_shift = 1; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index e9e256718ef4..1c9478e6e5d9 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -27,7 +27,6 @@ #include <linux/iopoll.h> #include <linux/spi/spi.h> -#include <linux/gpio.h> #include <linux/platform_data/spi-omap2-mcspi.h> @@ -1043,16 +1042,6 @@ static int omap2_mcspi_setup(struct spi_device *spi) spi->controller_state = cs; /* Link this to context save list */ list_add_tail(&cs->node, &ctx->cs); - - if (gpio_is_valid(spi->cs_gpio)) { - ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); - if (ret) { - dev_err(&spi->dev, "failed to request gpio\n"); - return ret; - } - gpio_direction_output(spi->cs_gpio, - !(spi->mode & SPI_CS_HIGH)); - } } ret = pm_runtime_get_sync(mcspi->dev); @@ -1080,9 +1069,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) kfree(cs); } - - if (gpio_is_valid(spi->cs_gpio)) - gpio_free(spi->cs_gpio); } static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data) @@ -1152,7 +1138,7 @@ static int omap2_mcspi_transfer_one(struct spi_master *master, omap2_mcspi_set_enable(spi, 0); - if (gpio_is_valid(spi->cs_gpio)) + if (spi->cs_gpiod) omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH); if (par_override || @@ -1241,7 +1227,7 @@ out: omap2_mcspi_set_enable(spi, 0); - if (gpio_is_valid(spi->cs_gpio)) + if (spi->cs_gpiod) omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH)); if (mcspi->fifo_depth > 0 && t) @@ -1431,6 +1417,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->dev.of_node = node; master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; + master->use_gpio_descriptors = true; platform_set_drvdata(pdev, master); diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 43f73db22f21..b57b8b3cc26e 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -708,7 +708,7 @@ static int orion_spi_probe(struct platform_device *pdev) /* * Only map one page for direct access. This is enough for the * simple TX transfer which only writes to the first word. - * This needs to get extended for the direct SPI-NOR / SPI-NAND + * This needs to get extended for the direct SPI NOR / SPI NAND * support, once this gets implemented. */ dir_acc = &spi->child[cs].direct_access; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 66028ebbc336..d1776fea287e 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -298,7 +298,7 @@ enum ssp_reading { READING_U32 }; -/** +/* * The type of writing going on on this chip */ enum ssp_writing { @@ -317,6 +317,7 @@ enum ssp_writing { * @extended_cr: 32 bit wide control register 0 with extra * features and extra features in CR1 as found in the ST variants * @pl023: supports a subset of the ST extensions called "PL023" + * @loopback: supports loopback mode * @internal_cs_ctrl: supports chip select control register */ struct vendor_data { @@ -353,11 +354,14 @@ struct vendor_data { * @read: the type of read currently going on * @write: the type of write currently going on * @exp_fifo_level: expected FIFO level + * @rx_lev_trig: receive FIFO watermark level which triggers IRQ + * @tx_lev_trig: transmit FIFO watermark level which triggers IRQ * @dma_rx_channel: optional channel for RX DMA * @dma_tx_channel: optional channel for TX DMA * @sgt_rx: scattertable for the RX transfer * @sgt_tx: scattertable for the TX transfer * @dummypage: a dummy page used for driving data on the bus with DMA + * @dma_running: indicates whether DMA is in operation * @cur_cs: current chip select (gpio) * @chipselects: list of chipselects (gpios) */ @@ -662,7 +666,7 @@ static void load_ssp_default_config(struct pl022 *pl022) writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); } -/** +/* * This will write to TX and read from RX according to the parameters * set in pl022. */ @@ -1237,6 +1241,8 @@ static inline void pl022_dma_remove(struct pl022 *pl022) /** * pl022_interrupt_handler - Interrupt handler for SSP controller + * @irq: IRQ number + * @dev_id: Local device data * * This function handles interrupts generated for an interrupt based transfer. * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the @@ -1334,7 +1340,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) return IRQ_HANDLED; } -/** +/* * This sets up the pointers to memory for the next message to * send out on the SPI bus. */ diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 0ea2d9a369d9..d8ee363fb714 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -28,11 +28,9 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> @@ -127,8 +125,6 @@ struct ppc4xx_spi { const unsigned char *tx; unsigned char *rx; - int *gpios; - struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */ struct spi_master *master; struct device *dev; @@ -260,27 +256,6 @@ static int spi_ppc4xx_setup(struct spi_device *spi) return 0; } -static void spi_ppc4xx_chipsel(struct spi_device *spi, int value) -{ - struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master); - unsigned int cs = spi->chip_select; - unsigned int cspol; - - /* - * If there are no chip selects at all, or if this is the special - * case of a non-existent (dummy) chip select, do nothing. - */ - - if (!hw->master->num_chipselect || hw->gpios[cs] == -EEXIST) - return; - - cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; - if (value == BITBANG_CS_INACTIVE) - cspol = !cspol; - - gpio_set_value(hw->gpios[cs], cspol); -} - static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id) { struct ppc4xx_spi *hw; @@ -359,19 +334,6 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw) dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0); } -static void free_gpios(struct ppc4xx_spi *hw) -{ - if (hw->master->num_chipselect) { - int i; - for (i = 0; i < hw->master->num_chipselect; i++) - if (gpio_is_valid(hw->gpios[i])) - gpio_free(hw->gpios[i]); - - kfree(hw->gpios); - hw->gpios = NULL; - } -} - /* * platform_device layer stuff... */ @@ -385,7 +347,6 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) struct device *dev = &op->dev; struct device_node *opbnp; int ret; - int num_gpios; const unsigned int *clk; master = spi_alloc_master(dev, sizeof *hw); @@ -399,74 +360,32 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) init_completion(&hw->done); - /* - * A count of zero implies a single SPI device without any chip-select. - * Note that of_gpio_count counts all gpios assigned to this spi master. - * This includes both "null" gpio's and real ones. - */ - num_gpios = of_gpio_count(np); - if (num_gpios > 0) { - int i; - - hw->gpios = kcalloc(num_gpios, sizeof(*hw->gpios), GFP_KERNEL); - if (!hw->gpios) { - ret = -ENOMEM; - goto free_master; - } - - for (i = 0; i < num_gpios; i++) { - int gpio; - enum of_gpio_flags flags; - - gpio = of_get_gpio_flags(np, i, &flags); - hw->gpios[i] = gpio; - - if (gpio_is_valid(gpio)) { - /* Real CS - set the initial state. */ - ret = gpio_request(gpio, np->name); - if (ret < 0) { - dev_err(dev, - "can't request gpio #%d: %d\n", - i, ret); - goto free_gpios; - } - - gpio_direction_output(gpio, - !!(flags & OF_GPIO_ACTIVE_LOW)); - } else if (gpio == -EEXIST) { - ; /* No CS, but that's OK. */ - } else { - dev_err(dev, "invalid gpio #%d: %d\n", i, gpio); - ret = -EINVAL; - goto free_gpios; - } - } - } - /* Setup the state for the bitbang driver */ bbp = &hw->bitbang; bbp->master = hw->master; bbp->setup_transfer = spi_ppc4xx_setupxfer; - bbp->chipselect = spi_ppc4xx_chipsel; bbp->txrx_bufs = spi_ppc4xx_txrx; bbp->use_dma = 0; bbp->master->setup = spi_ppc4xx_setup; bbp->master->cleanup = spi_ppc4xx_cleanup; bbp->master->bits_per_word_mask = SPI_BPW_MASK(8); + bbp->master->use_gpio_descriptors = true; + /* + * The SPI core will count the number of GPIO descriptors to figure + * out the number of chip selects available on the platform. + */ + bbp->master->num_chipselect = 0; /* the spi->mode bits understood by this driver: */ bbp->master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST; - /* this many pins in all GPIO controllers */ - bbp->master->num_chipselect = num_gpios > 0 ? num_gpios : 0; - /* Get the clock for the OPB */ opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb"); if (opbnp == NULL) { dev_err(dev, "OPB: cannot find node\n"); ret = -ENODEV; - goto free_gpios; + goto free_master; } /* Get the clock (Hz) for the OPB */ clk = of_get_property(opbnp, "clock-frequency", NULL); @@ -474,7 +393,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) dev_err(dev, "OPB: no clock-frequency property set\n"); of_node_put(opbnp); ret = -ENODEV; - goto free_gpios; + goto free_master; } hw->opb_freq = *clk; hw->opb_freq >>= 2; @@ -483,7 +402,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ret = of_address_to_resource(np, 0, &resource); if (ret) { dev_err(dev, "error while parsing device node resource\n"); - goto free_gpios; + goto free_master; } hw->mapbase = resource.start; hw->mapsize = resource_size(&resource); @@ -492,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) { dev_err(dev, "too small to map registers\n"); ret = -EINVAL; - goto free_gpios; + goto free_master; } /* Request IRQ */ @@ -501,7 +420,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) 0, "spi_ppc4xx_of", (void *)hw); if (ret) { dev_err(dev, "unable to allocate interrupt\n"); - goto free_gpios; + goto free_master; } if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) { @@ -538,8 +457,6 @@ map_io_error: release_mem_region(hw->mapbase, hw->mapsize); request_mem_error: free_irq(hw->irqnum, hw); -free_gpios: - free_gpios(hw); free_master: spi_master_put(master); @@ -556,7 +473,6 @@ static int spi_ppc4xx_of_remove(struct platform_device *op) release_mem_region(hw->mapbase, hw->mapsize); free_irq(hw->irqnum, hw); iounmap(hw->regs); - free_gpios(hw); spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 0040362b7162..814268405ab0 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1432,6 +1432,7 @@ static void cleanup(struct spi_device *spi) kfree(chip); } +#ifdef CONFIG_ACPI static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { { "INT33C0", LPSS_LPT_SSP }, { "INT33C1", LPSS_LPT_SSP }, @@ -1442,6 +1443,7 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { { }, }; MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); +#endif /* * PCI IDs of compound devices that integrate both host controller and private diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 9b8a5e1233c0..75a8a9428ff8 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -39,8 +39,9 @@ #define ROCKCHIP_SPI_RISR 0x0034 #define ROCKCHIP_SPI_ICR 0x0038 #define ROCKCHIP_SPI_DMACR 0x003c -#define ROCKCHIP_SPI_DMATDLR 0x0040 -#define ROCKCHIP_SPI_DMARDLR 0x0044 +#define ROCKCHIP_SPI_DMATDLR 0x0040 +#define ROCKCHIP_SPI_DMARDLR 0x0044 +#define ROCKCHIP_SPI_VERSION 0x0048 #define ROCKCHIP_SPI_TXDR 0x0400 #define ROCKCHIP_SPI_RXDR 0x0800 @@ -156,6 +157,8 @@ #define ROCKCHIP_SPI_MAX_TRANLEN 0xffff #define ROCKCHIP_SPI_MAX_CS_NUM 2 +#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002 +#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002 struct rockchip_spi { struct device *dev; @@ -206,17 +209,17 @@ static inline void wait_for_idle(struct rockchip_spi *rs) static u32 get_fifo_len(struct rockchip_spi *rs) { - u32 fifo; + u32 ver; - for (fifo = 2; fifo < 32; fifo++) { - writel_relaxed(fifo, rs->regs + ROCKCHIP_SPI_TXFTLR); - if (fifo != readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFTLR)) - break; - } - - writel_relaxed(0, rs->regs + ROCKCHIP_SPI_TXFTLR); + ver = readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION); - return (fifo == 31) ? 0 : fifo; + switch (ver) { + case ROCKCHIP_SPI_VER2_TYPE1: + case ROCKCHIP_SPI_VER2_TYPE2: + return 64; + default: + return 32; + } } static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) @@ -288,7 +291,7 @@ static void rockchip_spi_pio_writer(struct rockchip_spi *rs) static void rockchip_spi_pio_reader(struct rockchip_spi *rs) { u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR); - u32 rx_left = rs->rx_left - words; + u32 rx_left = (rs->rx_left > words) ? rs->rx_left - words : 0; /* the hardware doesn't allow us to change fifo threshold * level while spi is enabled, so instead make sure to leave @@ -384,6 +387,19 @@ static void rockchip_spi_dma_txcb(void *data) spi_finalize_current_transfer(ctlr); } +static u32 rockchip_spi_calc_burst_size(u32 data_len) +{ + u32 i; + + /* burst size: 1, 2, 4, 8 */ + for (i = 1; i < 8; i <<= 1) { + if (data_len & i) + break; + } + + return i; +} + static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, struct spi_controller *ctlr, struct spi_transfer *xfer) { @@ -397,7 +413,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, .direction = DMA_DEV_TO_MEM, .src_addr = rs->dma_addr_rx, .src_addr_width = rs->n_bytes, - .src_maxburst = 1, + .src_maxburst = rockchip_spi_calc_burst_size(xfer->len / + rs->n_bytes), }; dmaengine_slave_config(ctlr->dma_rx, &rxconf); @@ -525,7 +542,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs, writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR); - writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR); + writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1, + rs->regs + ROCKCHIP_SPI_DMARDLR); writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); /* the hardware only supports an even clock divisor, so diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c new file mode 100644 index 000000000000..ed3e548227f4 --- /dev/null +++ b/drivers/spi/spi-rpc-if.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// RPC-IF SPI/QSPI/Octa driver +// +// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp. +// Copyright (C) 2019 Macronix International Co., Ltd. +// Copyright (C) 2019 - 2020 Cogent Embedded, Inc. +// + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> + +#include <memory/renesas-rpc-if.h> + +#include <asm/unaligned.h> + +static void rpcif_spi_mem_prepare(struct spi_device *spi_dev, + const struct spi_mem_op *spi_op, + u64 *offs, size_t *len) +{ + struct rpcif *rpc = spi_controller_get_devdata(spi_dev->controller); + struct rpcif_op rpc_op = { }; + + rpc_op.cmd.opcode = spi_op->cmd.opcode; + rpc_op.cmd.buswidth = spi_op->cmd.buswidth; + + if (spi_op->addr.nbytes) { + rpc_op.addr.buswidth = spi_op->addr.buswidth; + rpc_op.addr.nbytes = spi_op->addr.nbytes; + rpc_op.addr.val = spi_op->addr.val; + } + + if (spi_op->dummy.nbytes) { + rpc_op.dummy.buswidth = spi_op->dummy.buswidth; + rpc_op.dummy.ncycles = spi_op->dummy.nbytes * 8 / + spi_op->dummy.buswidth; + } + + if (spi_op->data.nbytes || (offs && len)) { + rpc_op.data.buswidth = spi_op->data.buswidth; + rpc_op.data.nbytes = spi_op->data.nbytes; + switch (spi_op->data.dir) { + case SPI_MEM_DATA_IN: + rpc_op.data.dir = RPCIF_DATA_IN; + rpc_op.data.buf.in = spi_op->data.buf.in; + break; + case SPI_MEM_DATA_OUT: + rpc_op.data.dir = RPCIF_DATA_OUT; + rpc_op.data.buf.out = spi_op->data.buf.out; + break; + case SPI_MEM_NO_DATA: + rpc_op.data.dir = RPCIF_NO_DATA; + break; + } + } else { + rpc_op.data.dir = RPCIF_NO_DATA; + } + + rpcif_prepare(rpc, &rpc_op, offs, len); +} + +static bool rpcif_spi_mem_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(mem, op)) + return false; + + if (op->data.buswidth > 4 || op->addr.buswidth > 4 || + op->dummy.buswidth > 4 || op->cmd.buswidth > 4 || + op->addr.nbytes > 4) + return false; + + return true; +} + +static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) +{ + struct rpcif *rpc = + spi_controller_get_devdata(desc->mem->spi->controller); + + if (offs + desc->info.offset + len > U32_MAX) + return -EINVAL; + + rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + + return rpcif_dirmap_read(rpc, offs, len, buf); +} + +static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) +{ + struct rpcif *rpc = + spi_controller_get_devdata(desc->mem->spi->controller); + + if (desc->info.offset + desc->info.length > U32_MAX) + return -ENOTSUPP; + + if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + return -ENOTSUPP; + + if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) + return -ENOTSUPP; + + if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + return -ENOTSUPP; + + return 0; +} + +static int rpcif_spi_mem_exec_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct rpcif *rpc = + spi_controller_get_devdata(mem->spi->controller); + + rpcif_spi_mem_prepare(mem->spi, op, NULL, NULL); + + return rpcif_manual_xfer(rpc); +} + +static const struct spi_controller_mem_ops rpcif_spi_mem_ops = { + .supports_op = rpcif_spi_mem_supports_op, + .exec_op = rpcif_spi_mem_exec_op, + .dirmap_create = rpcif_spi_mem_dirmap_create, + .dirmap_read = rpcif_spi_mem_dirmap_read, +}; + +static int rpcif_spi_probe(struct platform_device *pdev) +{ + struct device *parent = pdev->dev.parent; + struct spi_controller *ctlr; + struct rpcif *rpc; + int error; + + ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc)); + if (!ctlr) + return -ENOMEM; + + rpc = spi_controller_get_devdata(ctlr); + rpcif_sw_init(rpc, parent); + + platform_set_drvdata(pdev, ctlr); + + ctlr->dev.of_node = parent->of_node; + + rpcif_enable_rpm(rpc); + + ctlr->num_chipselect = 1; + ctlr->mem_ops = &rpcif_spi_mem_ops; + + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD; + ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX; + + rpcif_hw_init(rpc, false); + + error = spi_register_controller(ctlr); + if (error) { + dev_err(&pdev->dev, "spi_register_controller failed\n"); + goto err_put_ctlr; + } + return 0; + +err_put_ctlr: + rpcif_disable_rpm(rpc); + spi_controller_put(ctlr); + + return error; +} + +static int rpcif_spi_remove(struct platform_device *pdev) +{ + struct spi_controller *ctlr = platform_get_drvdata(pdev); + struct rpcif *rpc = spi_controller_get_devdata(ctlr); + + spi_unregister_controller(ctlr); + rpcif_disable_rpm(rpc); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int 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) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + + return spi_controller_resume(ctlr); +} + +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, + }, +}; +module_platform_driver(rpcif_spi_driver); + +MODULE_DESCRIPTION("Renesas RPC-IF SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index cf67ea60dc0e..924b24441789 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -130,9 +130,11 @@ struct s3c64xx_spi_dma_data { * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register. * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter. * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter. + * @quirks: Bitmask of known quirks * @high_speed: True, if the controller supports HIGH_SPEED_EN bit. * @clk_from_cmu: True, if the controller does not include a clock mux and * prescaler unit. + * @clk_ioclk: True if clock is present on this device * * The Samsung s3c64xx SPI controller are used on various Samsung SoC's but * differ in some aspects such as the size of the fifo and spi bus clock @@ -154,6 +156,7 @@ struct s3c64xx_spi_port_config { * @clk: Pointer to the spi clock. * @src_clk: Pointer to the clock used to generate SPI signals. * @ioclk: Pointer to the i/o clock between master and slave + * @pdev: Pointer to device's platform device data * @master: Pointer to the SPI Protocol master. * @cntrlr_info: Platform specific data for the controller this driver manages. * @lock: Controller specific lock. @@ -166,7 +169,11 @@ struct s3c64xx_spi_port_config { * @xfer_completion: To indicate completion of xfer task. * @cur_mode: Stores the active configuration of the controller. * @cur_bpw: Stores the active bits per word settings. - * @cur_speed: Stores the active xfer clock speed. + * @cur_speed: Current clock speed + * @rx_dma: Local receive DMA data (e.g. chan and direction) + * @tx_dma: Local transmit DMA data (e.g. chan and direction) + * @port_conf: Local SPI port configuartion data + * @port_id: Port identification number */ struct s3c64xx_spi_driver_data { void __iomem *regs; diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index cbfac6596fad..1fdfc6e6691d 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -198,7 +198,7 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool enable) static size_t sun4i_spi_max_transfer_size(struct spi_device *spi) { - return SUN4I_FIFO_DEPTH - 1; + return SUN4I_MAX_XFER_SIZE - 1; } static int sun4i_spi_transfer_one(struct spi_master *master, diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index fa11cc0e809b..19238e1b76b4 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -7,6 +7,7 @@ * Maxime Ripard <maxime.ripard@free-electrons.com> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> @@ -58,10 +59,8 @@ #define SUN6I_FIFO_CTL_TF_RST BIT(31) #define SUN6I_FIFO_STA_REG 0x1c -#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f -#define SUN6I_FIFO_STA_RF_CNT_BITS 0 -#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f -#define SUN6I_FIFO_STA_TF_CNT_BITS 16 +#define SUN6I_FIFO_STA_RF_CNT_MASK GENMASK(7, 0) +#define SUN6I_FIFO_STA_TF_CNT_MASK GENMASK(23, 16) #define SUN6I_CLK_CTL_REG 0x24 #define SUN6I_CLK_CTL_CDR2_MASK 0xff @@ -73,13 +72,10 @@ #define SUN6I_MAX_XFER_SIZE 0xffffff #define SUN6I_BURST_CNT_REG 0x30 -#define SUN6I_BURST_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE) #define SUN6I_XMIT_CNT_REG 0x34 -#define SUN6I_XMIT_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE) #define SUN6I_BURST_CTL_CNT_REG 0x38 -#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE) #define SUN6I_TXDATA_REG 0x200 #define SUN6I_RXDATA_REG 0x300 @@ -109,21 +105,18 @@ static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value) writel(value, sspi->base_addr + reg); } -static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi) +static inline u32 sun6i_spi_get_rx_fifo_count(struct sun6i_spi *sspi) { u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG); - reg >>= SUN6I_FIFO_STA_TF_CNT_BITS; - - return reg & SUN6I_FIFO_STA_TF_CNT_MASK; + return FIELD_GET(SUN6I_FIFO_STA_RF_CNT_MASK, reg); } -static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask) +static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi) { - u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG); + u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG); - reg |= mask; - sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg); + return FIELD_GET(SUN6I_FIFO_STA_TF_CNT_MASK, reg); } static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask) @@ -134,18 +127,13 @@ static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask) sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg); } -static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) +static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi) { - u32 reg, cnt; + u32 len; u8 byte; /* See how much data is available */ - reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG); - reg &= SUN6I_FIFO_STA_RF_CNT_MASK; - cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS; - - if (len > cnt) - len = cnt; + len = sun6i_spi_get_rx_fifo_count(sspi); while (len--) { byte = readb(sspi->base_addr + SUN6I_RXDATA_REG); @@ -154,15 +142,16 @@ static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) } } -static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len) +static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi) { u32 cnt; + int len; u8 byte; /* See how much data we can fit */ cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi); - len = min3(len, (int)cnt, sspi->len); + len = min((int)cnt, sspi->len); while (len--) { byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; @@ -201,7 +190,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout; unsigned int start, end, tx_time; unsigned int trig_level; - unsigned int tx_len = 0; + unsigned int tx_len = 0, rx_len = 0; int ret = 0; u32 reg; @@ -256,10 +245,12 @@ static int sun6i_spi_transfer_one(struct spi_master *master, * If it's a TX only transfer, we don't want to fill the RX * FIFO with bogus data */ - if (sspi->rx_buf) + if (sspi->rx_buf) { reg &= ~SUN6I_TFR_CTL_DHB; - else + rx_len = tfr->len; + } else { reg |= SUN6I_TFR_CTL_DHB; + } /* We want to control the chip select manually */ reg |= SUN6I_TFR_CTL_CS_MANUAL; @@ -291,9 +282,11 @@ static int sun6i_spi_transfer_one(struct spi_master *master, div_cdr2 = DIV_ROUND_UP(div_cdr1, 2); if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) { reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS; + tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2); } else { div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1)); reg = SUN6I_CLK_CTL_CDR1(div); + tfr->effective_speed_hz = mclk_rate / (1 << div); } sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg); @@ -303,20 +296,22 @@ static int sun6i_spi_transfer_one(struct spi_master *master, tx_len = tfr->len; /* Setup the counters */ - sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len)); - sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len)); - sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, - SUN6I_BURST_CTL_CNT_STC(tx_len)); + sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len); + sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len); + sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len); /* Fill the TX FIFO */ - sun6i_spi_fill_fifo(sspi, sspi->fifo_depth); + sun6i_spi_fill_fifo(sspi); /* Enable the interrupts */ - sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC); - sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC | - SUN6I_INT_CTL_RF_RDY); + reg = SUN6I_INT_CTL_TC; + + if (rx_len > sspi->fifo_depth) + reg |= SUN6I_INT_CTL_RF_RDY; if (tx_len > sspi->fifo_depth) - sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ); + reg |= SUN6I_INT_CTL_TF_ERQ; + + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg); /* Start the transfer */ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); @@ -333,10 +328,8 @@ static int sun6i_spi_transfer_one(struct spi_master *master, dev_name(&spi->dev), tfr->len, tfr->speed_hz, jiffies_to_msecs(end - start), tx_time); ret = -ETIMEDOUT; - goto out; } -out: sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); return ret; @@ -350,14 +343,14 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id) /* Transfer complete */ if (status & SUN6I_INT_CTL_TC) { sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC); - sun6i_spi_drain_fifo(sspi, sspi->fifo_depth); + sun6i_spi_drain_fifo(sspi); complete(&sspi->done); return IRQ_HANDLED; } /* Receive FIFO 3/4 full */ if (status & SUN6I_INT_CTL_RF_RDY) { - sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH); + sun6i_spi_drain_fifo(sspi); /* Only clear the interrupt _after_ draining the FIFO */ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY); return IRQ_HANDLED; @@ -365,7 +358,7 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id) /* Transmit FIFO 3/4 empty */ if (status & SUN6I_INT_CTL_TF_ERQ) { - sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH); + sun6i_spi_fill_fifo(sspi); if (!sspi->len) /* nothing left to transmit */ diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 366a3e5cca6b..3c41649698a5 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -2,7 +2,7 @@ /* * TI QSPI driver * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com * Author: Sourav Poddar <sourav.poddar@ti.com> */ diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index d7ea6af74743..6df2aeff2843 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -122,6 +122,7 @@ struct pch_spi_dma_ctrl { /** * struct pch_spi_data - Holds the SPI channel specific details * @io_remap_addr: The remapped PCI base address + * @io_base_addr: Base address * @master: Pointer to the SPI master structure * @work: Reference to work queue handler * @wait: Wait queue for waking up upon receiving an @@ -138,8 +139,8 @@ struct pch_spi_dma_ctrl { * transfer * @rx_index: Receive data count; for bookkeeping during * transfer - * @tx_buff: Buffer for data to be transmitted - * @rx_index: Buffer for Received data + * @pkt_tx_buff: Buffer for data to be transmitted + * @pkt_rx_buff: Buffer for received data * @n_curnt_chip: The chip number that this SPI driver currently * operates on * @current_chip: Reference to the current chip that this SPI @@ -151,7 +152,10 @@ struct pch_spi_dma_ctrl { * @board_dat: Reference to the SPI device data structure * @plat_dev: platform_device structure * @ch: SPI channel number + * @dma: Local DMA information + * @use_dma: True if DMA is to be used * @irq_reg_sts: Status of IRQ registration + * @save_total_len: Save length while data is being transferred */ struct pch_spi_data { void __iomem *io_remap_addr; @@ -1631,64 +1635,37 @@ static void pch_spi_remove(struct pci_dev *pdev) kfree(pd_dev_save); } -#ifdef CONFIG_PM -static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused pch_spi_suspend(struct device *dev) { - int retval; - struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev); + struct pch_pd_dev_save *pd_dev_save = dev_get_drvdata(dev); - dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); + dev_dbg(dev, "%s ENTRY\n", __func__); pd_dev_save->board_dat->suspend_sts = true; - /* save config space */ - retval = pci_save_state(pdev); - if (retval == 0) { - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - } else { - dev_err(&pdev->dev, "%s pci_save_state failed\n", __func__); - } - - return retval; + return 0; } -static int pch_spi_resume(struct pci_dev *pdev) +static int __maybe_unused pch_spi_resume(struct device *dev) { - int retval; - struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev); - dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); + struct pch_pd_dev_save *pd_dev_save = dev_get_drvdata(dev); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); + dev_dbg(dev, "%s ENTRY\n", __func__); - retval = pci_enable_device(pdev); - if (retval < 0) { - dev_err(&pdev->dev, - "%s pci_enable_device failed\n", __func__); - } else { - pci_enable_wake(pdev, PCI_D3hot, 0); - - /* set suspend status to false */ - pd_dev_save->board_dat->suspend_sts = false; - } + /* set suspend status to false */ + pd_dev_save->board_dat->suspend_sts = false; - return retval; + return 0; } -#else -#define pch_spi_suspend NULL -#define pch_spi_resume NULL -#endif +static SIMPLE_DEV_PM_OPS(pch_spi_pm_ops, pch_spi_suspend, pch_spi_resume); static struct pci_driver pch_spi_pcidev_driver = { .name = "pch_spi", .id_table = pch_spi_pcidev_id, .probe = pch_spi_probe, .remove = pch_spi_remove, - .suspend = pch_spi_suspend, - .resume = pch_spi_resume, + .driver.pm = &pch_spi_pm_ops, }; static int __init pch_spi_init(void) diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 17641157354d..5d8a5ee62fa2 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -119,6 +119,7 @@ /** * struct zynq_qspi - Defines qspi driver instance + * @dev: Pointer to the this device's information * @regs: Virtual address of the QSPI controller registers * @refclk: Pointer to the peripheral clock * @pclk: Pointer to the APB clock @@ -316,7 +317,7 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert) /** * zynq_qspi_config_op - Configure QSPI controller for specified transfer * @xqspi: Pointer to the zynq_qspi structure - * @qspi: Pointer to the spi_device structure + * @spi: Pointer to the spi_device structure * * Sets the operational mode of QSPI controller for the next QSPI transfer and * sets the requested clock frequency. @@ -527,20 +528,21 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master); int err = 0, i; u8 *tmpbuf; + u8 opcode = op->cmd.opcode; dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n", - op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, + opcode, op->cmd.buswidth, op->addr.buswidth, op->dummy.buswidth, op->data.buswidth); zynq_qspi_chipselect(mem->spi, true); zynq_qspi_config_op(xqspi, mem->spi); - if (op->cmd.opcode) { + if (op->cmd.nbytes) { reinit_completion(&xqspi->data_completion); - xqspi->txbuf = (u8 *)&op->cmd.opcode; + xqspi->txbuf = &opcode; xqspi->rxbuf = NULL; - xqspi->tx_bytes = sizeof(op->cmd.opcode); - xqspi->rx_bytes = sizeof(op->cmd.opcode); + xqspi->tx_bytes = op->cmd.nbytes; + xqspi->rx_bytes = op->cmd.nbytes; zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true); zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET, ZYNQ_QSPI_IXR_RXTX_MASK); diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 811c97a7c858..e17a20125255 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -197,8 +197,8 @@ static inline void zynqmp_gqspi_write(struct zynqmp_qspi *xqspi, u32 offset, /** * zynqmp_gqspi_selectslave: For selection of slave device * @instanceptr: Pointer to the zynqmp_qspi structure - * @flashcs: For chip select - * @flashbus: To check which bus is selected- upper or lower + * @slavecs: For chip select + * @slavebus: To check which bus is selected- upper or lower */ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr, u8 slavecs, u8 slavebus) @@ -892,7 +892,7 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master, /** * zynqmp_qspi_suspend: Suspend method for the QSPI driver - * @_dev: Address of the platform_device structure + * @dev: Address of the platform_device structure * * This function stops the QSPI driver queue and disables the QSPI controller * diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8158e281f354..0b260484b4f5 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -778,6 +778,17 @@ static void spi_set_cs(struct spi_device *spi, bool enable) { bool enable1 = enable; + /* + * Avoid calling into the driver (or doing delays) if the chip select + * isn't actually changing from the last time this was called. + */ + if ((spi->controller->last_cs_enable == enable) && + (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH))) + return; + + spi->controller->last_cs_enable = enable; + spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH; + if (!spi->controller->set_cs_timing) { if (enable1) spi_delay_exec(&spi->controller->cs_setup, NULL); @@ -982,6 +993,8 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); } + ctlr->cur_msg_mapped = false; + return 0; } #else /* !CONFIG_HAS_DMA */ @@ -1234,8 +1247,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, if (xfer->tx_buf || xfer->rx_buf) { reinit_completion(&ctlr->xfer_completion); +fallback_pio: ret = ctlr->transfer_one(ctlr, msg->spi, xfer); if (ret < 0) { + if (ctlr->cur_msg_mapped && + (xfer->error & SPI_TRANS_FAIL_NO_START)) { + __spi_unmap_msg(ctlr, msg); + ctlr->fallback = true; + xfer->error &= ~SPI_TRANS_FAIL_NO_START; + goto fallback_pio; + } + SPI_STATISTICS_INCREMENT_FIELD(statm, errors); SPI_STATISTICS_INCREMENT_FIELD(stats, @@ -1314,6 +1336,14 @@ void spi_finalize_current_transfer(struct spi_controller *ctlr) } EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); +static void spi_idle_runtime_pm(struct spi_controller *ctlr) +{ + if (ctlr->auto_runtime_pm) { + pm_runtime_mark_last_busy(ctlr->dev.parent); + pm_runtime_put_autosuspend(ctlr->dev.parent); + } +} + /** * __spi_pump_messages - function which processes spi message queue * @ctlr: controller to process queue for @@ -1346,7 +1376,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) /* If another context is idling the device then defer */ if (ctlr->idling) { - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); return; } @@ -1358,10 +1388,17 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) return; } - /* Only do teardown in the thread */ + /* Defer any non-atomic teardown to the thread */ if (!in_kthread) { - kthread_queue_work(&ctlr->kworker, - &ctlr->pump_messages); + if (!ctlr->dummy_rx && !ctlr->dummy_tx && + !ctlr->unprepare_transfer_hardware) { + spi_idle_runtime_pm(ctlr); + ctlr->busy = false; + trace_spi_controller_idle(ctlr); + } else { + kthread_queue_work(ctlr->kworker, + &ctlr->pump_messages); + } spin_unlock_irqrestore(&ctlr->queue_lock, flags); return; } @@ -1378,10 +1415,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) ctlr->unprepare_transfer_hardware(ctlr)) dev_err(&ctlr->dev, "failed to unprepare transfer hardware\n"); - if (ctlr->auto_runtime_pm) { - pm_runtime_mark_last_busy(ctlr->dev.parent); - pm_runtime_put_autosuspend(ctlr->dev.parent); - } + spi_idle_runtime_pm(ctlr); trace_spi_controller_idle(ctlr); spin_lock_irqsave(&ctlr->queue_lock, flags); @@ -1596,7 +1630,7 @@ static void spi_set_thread_rt(struct spi_controller *ctlr) dev_info(&ctlr->dev, "will run message pump with realtime priority\n"); - sched_setscheduler(ctlr->kworker_task, SCHED_FIFO, ¶m); + sched_setscheduler(ctlr->kworker->task, SCHED_FIFO, ¶m); } static int spi_init_queue(struct spi_controller *ctlr) @@ -1604,13 +1638,12 @@ static int spi_init_queue(struct spi_controller *ctlr) ctlr->running = false; ctlr->busy = false; - kthread_init_worker(&ctlr->kworker); - ctlr->kworker_task = kthread_run(kthread_worker_fn, &ctlr->kworker, - "%s", dev_name(&ctlr->dev)); - if (IS_ERR(ctlr->kworker_task)) { - dev_err(&ctlr->dev, "failed to create message pump task\n"); - return PTR_ERR(ctlr->kworker_task); + ctlr->kworker = kthread_create_worker(0, dev_name(&ctlr->dev)); + if (IS_ERR(ctlr->kworker)) { + dev_err(&ctlr->dev, "failed to create message pump kworker\n"); + return PTR_ERR(ctlr->kworker); } + kthread_init_work(&ctlr->pump_messages, spi_pump_messages); /* @@ -1693,7 +1726,8 @@ void spi_finalize_current_message(struct spi_controller *ctlr) spin_lock_irqsave(&ctlr->queue_lock, flags); ctlr->cur_msg = NULL; ctlr->cur_msg_prepared = false; - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + ctlr->fallback = false; + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); trace_spi_message_done(mesg); @@ -1719,7 +1753,7 @@ static int spi_start_queue(struct spi_controller *ctlr) ctlr->cur_msg = NULL; spin_unlock_irqrestore(&ctlr->queue_lock, flags); - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); return 0; } @@ -1775,8 +1809,7 @@ static int spi_destroy_queue(struct spi_controller *ctlr) return ret; } - kthread_flush_worker(&ctlr->kworker); - kthread_stop(ctlr->kworker_task); + kthread_destroy_worker(ctlr->kworker); return 0; } @@ -1799,7 +1832,7 @@ static int __spi_queued_transfer(struct spi_device *spi, list_add_tail(&msg->queue, &ctlr->queue); if (!ctlr->busy && need_pump) - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + kthread_queue_work(ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); return 0; diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 59e07675ef86..455e99c4958e 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -224,6 +224,11 @@ static int spidev_message(struct spidev_data *spidev, for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; n; n--, k_tmp++, u_tmp++) { + /* Ensure that also following allocations from rx_buf/tx_buf will meet + * DMA alignment requirements. + */ + unsigned int len_aligned = ALIGN(u_tmp->len, ARCH_KMALLOC_MINALIGN); + k_tmp->len = u_tmp->len; total += k_tmp->len; @@ -239,17 +244,17 @@ static int spidev_message(struct spidev_data *spidev, if (u_tmp->rx_buf) { /* this transfer needs space in RX bounce buffer */ - rx_total += k_tmp->len; + rx_total += len_aligned; if (rx_total > bufsiz) { status = -EMSGSIZE; goto done; } k_tmp->rx_buf = rx_buf; - rx_buf += k_tmp->len; + rx_buf += len_aligned; } if (u_tmp->tx_buf) { /* this transfer needs space in TX bounce buffer */ - tx_total += k_tmp->len; + tx_total += len_aligned; if (tx_total > bufsiz) { status = -EMSGSIZE; goto done; @@ -259,7 +264,7 @@ static int spidev_message(struct spidev_data *spidev, (uintptr_t) u_tmp->tx_buf, u_tmp->len)) goto done; - tx_buf += k_tmp->len; + tx_buf += len_aligned; } k_tmp->cs_change = !!u_tmp->cs_change; @@ -293,16 +298,16 @@ static int spidev_message(struct spidev_data *spidev, goto done; /* copy any rx data out of bounce buffer */ - rx_buf = spidev->rx_buffer; - for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) { + for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; + n; + n--, k_tmp++, u_tmp++) { if (u_tmp->rx_buf) { if (copy_to_user((u8 __user *) - (uintptr_t) u_tmp->rx_buf, rx_buf, + (uintptr_t) u_tmp->rx_buf, k_tmp->rx_buf, u_tmp->len)) { status = -EFAULT; goto done; } - rx_buf += u_tmp->len; } } status = total; |