From 1e695983251029dc0b0fc516290077539df400ff Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Wed, 18 Sep 2019 09:04:35 +0100 Subject: spi: dw: Add basic runtime PM support Enable runtime PM so that the clock used to access the registers in the peripheral is turned on using a clock domain. Signed-off-by: Phil Edworthy Signed-off-by: Gareth Williams Link: https://lore.kernel.org/r/1568793876-9009-4-git-send-email-gareth.williams.jx@renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 9a49e073e8b7..54ed6eb3e252 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -493,10 +494,13 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->dev.of_node = dev->of_node; master->dev.fwnode = dev->fwnode; master->flags = SPI_MASTER_GPIO_SS; + master->auto_runtime_pm = true; if (dws->set_cs) master->set_cs = dws->set_cs; + pm_runtime_enable(dev); + /* Basic HW init */ spi_hw_init(dev, dws); @@ -525,6 +529,7 @@ err_dma_exit: spi_enable_chip(dws, 0); free_irq(dws->irq, master); err_free_master: + pm_runtime_disable(dev); spi_controller_put(master); return ret; } @@ -539,6 +544,9 @@ void dw_spi_remove_host(struct dw_spi *dws) spi_shutdown_chip(dws); + if (dws->master) + pm_runtime_disable(&dws->master->dev); + free_irq(dws->irq, dws->master); } EXPORT_SYMBOL_GPL(dw_spi_remove_host); -- cgit From 3ade3a37bdd77319dd7865228402cf1669c9b678 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Wed, 18 Sep 2019 09:04:36 +0100 Subject: spi: dw: Add compatible string for Renesas RZ/N1 SPI Controller The Renesas RZ/N1 SPI Controller is based on the Synopsys DW SSI, but has additional registers for software CS control and DMA. This patch does not address the changes required for DMA support, it simply adds the compatible string. The CS registers are not needed as Linux can use gpios for the CS signals. Signed-off-by: Gareth Williams Signed-off-by: Phil Edworthy Link: https://lore.kernel.org/r/1568793876-9009-5-git-send-email-gareth.williams.jx@renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mmio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index bd46fca3f094..b5ce8bd58d9e 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -223,6 +223,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = { { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init}, { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init}, { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init}, + { .compatible = "renesas,rzn1-spi", }, { /* end of table */} }; MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); -- cgit From e61bb114d41ddf6ae5bf05a0109fc13116550c7d Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 19 Sep 2019 17:40:34 +0200 Subject: spi: atmel: Remove AVR32 leftover AV32 support has been from the kernel a few release ago, but there was still some specific macro for this architecture in this driver. Lets remove it. Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20190919154034.7489-1-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index acf318e7330c..3ed5e663da6f 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -222,37 +222,13 @@ | SPI_BF(name, value)) /* Register access macros */ -#ifdef CONFIG_AVR32 -#define spi_readl(port, reg) \ - __raw_readl((port)->regs + SPI_##reg) -#define spi_writel(port, reg, value) \ - __raw_writel((value), (port)->regs + SPI_##reg) - -#define spi_readw(port, reg) \ - __raw_readw((port)->regs + SPI_##reg) -#define spi_writew(port, reg, value) \ - __raw_writew((value), (port)->regs + SPI_##reg) - -#define spi_readb(port, reg) \ - __raw_readb((port)->regs + SPI_##reg) -#define spi_writeb(port, reg, value) \ - __raw_writeb((value), (port)->regs + SPI_##reg) -#else #define spi_readl(port, reg) \ readl_relaxed((port)->regs + SPI_##reg) #define spi_writel(port, reg, value) \ writel_relaxed((value), (port)->regs + SPI_##reg) - -#define spi_readw(port, reg) \ - readw_relaxed((port)->regs + SPI_##reg) #define spi_writew(port, reg, value) \ writew_relaxed((value), (port)->regs + SPI_##reg) -#define spi_readb(port, reg) \ - readb_relaxed((port)->regs + SPI_##reg) -#define spi_writeb(port, reg, value) \ - writeb_relaxed((value), (port)->regs + SPI_##reg) -#endif /* use PIO for small transfers, avoiding DMA setup/teardown overhead and * cache operations; better heuristics consider wordsize and bitrate. */ -- cgit From 539ff2488af87f25f2c090fd74ced55bd966e5a9 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 19 Sep 2019 22:25:02 +0200 Subject: spi: mxic: Ensure width is respected in spi-mem operations Make use of a core helper to ensure the desired width is respected when calling spi-mem operators. Suggested-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20190919202504.9619-2-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-mxic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index f48563c09b97..409bfa163647 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -346,7 +346,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem, if (op->addr.nbytes > 7) return false; - return true; + return spi_mem_default_supports_op(mem, op); } static int mxic_spi_mem_exec_op(struct spi_mem *mem, -- cgit From 22262695f46b68659ba98a12e275df388c74968c Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 21 Sep 2019 14:16:49 +0200 Subject: spi: lantiq-ssc: Use devm_platform_ioremap_resource() in lantiq_ssc_probe() Simplify this function implementation by using a known wrapper function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://lore.kernel.org/r/230495a7-b754-bc6a-05e0-059a6b6c643d@web.de Signed-off-by: Mark Brown --- drivers/spi/spi-lantiq-ssc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index 9dfe8b04e688..1fd7ee53d451 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -797,7 +797,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct spi_master *master; - struct resource *res; struct lantiq_ssc_spi *spi; const struct lantiq_ssc_hwcfg *hwcfg; const struct of_device_id *match; @@ -812,12 +811,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev) } hwcfg = match->data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to get resources\n"); - return -ENXIO; - } - rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME); if (rx_irq < 0) return -ENXIO; @@ -839,8 +832,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev) spi->dev = dev; spi->hwcfg = hwcfg; platform_set_drvdata(pdev, spi); - - spi->regbase = devm_ioremap_resource(dev, res); + spi->regbase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(spi->regbase)) { err = PTR_ERR(spi->regbase); goto err_master_put; -- cgit From 5dd381e71994ab554f711afe89b5a6157bdcd19d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 21 Sep 2019 14:45:40 +0200 Subject: spi: mediatek: Use devm_platform_ioremap_resource() in mtk_spi_probe() Simplify this function implementation by using a known wrapper function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://lore.kernel.org/r/478e0df1-e800-8cf1-f9b3-d72f8e26aa0b@web.de Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 6888a4dcff6d..25fe149a8d9a 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -619,7 +619,6 @@ static int mtk_spi_probe(struct platform_device *pdev) struct spi_master *master; struct mtk_spi *mdata; const struct of_device_id *of_id; - struct resource *res; int i, irq, ret, addr_bits; master = spi_alloc_master(&pdev->dev, sizeof(*mdata)); @@ -682,15 +681,7 @@ static int mtk_spi_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, master); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_err(&pdev->dev, "failed to determine base address\n"); - goto err_put_master; - } - - mdata->base = devm_ioremap_resource(&pdev->dev, res); + mdata->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mdata->base)) { ret = PTR_ERR(mdata->base); goto err_put_master; -- cgit From 6cdcb5d394413d906773f1ae2efaa86485d6d6e1 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 21 Sep 2019 15:12:33 +0200 Subject: spi: mediatek: Use devm_platform_ioremap_resource() in mtk_spi_slave_probe() Simplify this function implementation by using a known wrapper function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://lore.kernel.org/r/225b76ca-a367-4bef-d8ce-42c7af9242a5@web.de Signed-off-by: Mark Brown --- drivers/spi/spi-slave-mt27xx.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index 61bc43b0fe57..44edaa360405 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -368,7 +368,6 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) { struct spi_controller *ctlr; struct mtk_spi_slave *mdata; - struct resource *res; int irq, ret; ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata)); @@ -392,17 +391,8 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctlr); init_completion(&mdata->xfer_done); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_err(&pdev->dev, "failed to determine base address\n"); - goto err_put_ctlr; - } - mdata->dev = &pdev->dev; - - mdata->base = devm_ioremap_resource(&pdev->dev, res); + mdata->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mdata->base)) { ret = PTR_ERR(mdata->base); goto err_put_ctlr; -- cgit From 3f049e7df22e563b04fd576bdc37e6b3e2c7a996 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 21 Sep 2019 15:35:08 +0200 Subject: spi: xtensa-xtfpga: Use devm_platform_ioremap_resource() in xtfpga_spi_probe() Simplify this function implementation by using a known wrapper function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://lore.kernel.org/r/178bb78e-714f-645f-d819-5732870c4272@web.de Signed-off-by: Mark Brown --- drivers/spi/spi-xtensa-xtfpga.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index 86516eb1e143..fc2b5eb7d614 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -80,7 +80,6 @@ static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on) static int xtfpga_spi_probe(struct platform_device *pdev) { struct xtfpga_spi *xspi; - struct resource *mem; int ret; struct spi_master *master; @@ -97,14 +96,7 @@ static int xtfpga_spi_probe(struct platform_device *pdev) xspi->bitbang.master = master; xspi->bitbang.chipselect = xtfpga_spi_chipselect; xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err; - } - xspi->regs = devm_ioremap_resource(&pdev->dev, mem); + xspi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(xspi->regs)) { ret = PTR_ERR(xspi->regs); goto err; -- cgit From f4b323905d8b3e28b2a9cef9325dbec1b0f7f064 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 24 Sep 2019 13:05:47 +0200 Subject: spi: Introduce dspi_slave_abort() function for NXP's dspi SPI driver This change provides the dspi_slave_abort() function, which is a callback for slave_abort() method of SPI controller generic driver. As in the SPI slave mode the transmission is driven by master, any distortion may cause the slave to enter undefined internal state. To avoid this problem the dspi_slave_abort() terminates all pending and ongoing DMA transactions (with sync) and clears internal FIFOs. Signed-off-by: Lukasz Majewski Link: https://lore.kernel.org/r/20190924110547.14770-3-lukma@denx.de Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index bec758e978fb..2c0f211eed87 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1006,6 +1006,25 @@ static void dspi_init(struct fsl_dspi *dspi) SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1)); } +static int dspi_slave_abort(struct spi_master *master) +{ + struct fsl_dspi *dspi = spi_master_get_devdata(master); + + /* + * Terminate all pending DMA transactions for the SPI working + * in SLAVE mode. + */ + dmaengine_terminate_sync(dspi->dma->chan_rx); + dmaengine_terminate_sync(dspi->dma->chan_tx); + + /* Clear the internal DSPI RX and TX FIFO buffers */ + regmap_update_bits(dspi->regmap, SPI_MCR, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); + + return 0; +} + static int dspi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1030,6 +1049,7 @@ static int dspi_probe(struct platform_device *pdev) ctlr->dev.of_node = pdev->dev.of_node; ctlr->cleanup = dspi_cleanup; + ctlr->slave_abort = dspi_slave_abort; ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; pdata = dev_get_platdata(&pdev->dev); -- cgit From 1b0a2b2d3ccb98cf998816d87f7193139d54579e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 26 Sep 2019 12:37:01 +0100 Subject: spi: fsl-lpspi: clean up indentation issue The complete call is indented incorrectly, remove the extraneous tabs. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190926113701.26986-1-colin.king@canonical.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index d08e9324140e..5efd73cd0ead 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -779,7 +779,7 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id) if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) { writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR); - complete(&fsl_lpspi->xfer_done); + complete(&fsl_lpspi->xfer_done); return IRQ_HANDLED; } -- cgit From 16c3e058036a6f5be542962e487d428518edcb45 Mon Sep 17 00:00:00 2001 From: Kuldeep Singh Date: Tue, 1 Oct 2019 14:29:16 +0530 Subject: spi: spi-fsl-qspi: Introduce variable to fix different invalid master Id Different platforms have different Master with different SourceID on AHB bus. The 0X0E Master ID is used by cluster 3 in case of LS2088A. So, patch introduce an invalid master id variable to fix invalid mastered on different platforms. Signed-off-by: Suresh Gupta Signed-off-by: Kuldeep Singh Link: https://lore.kernel.org/r/1569920356-8953-1-git-send-email-kuldeep.singh@nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-qspi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index c02e24c01136..51385b0927e3 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -63,6 +63,11 @@ #define QUADSPI_IPCR 0x08 #define QUADSPI_IPCR_SEQID(x) ((x) << 24) +#define QUADSPI_BUF0CR 0x10 +#define QUADSPI_BUF1CR 0x14 +#define QUADSPI_BUF2CR 0x18 +#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe + #define QUADSPI_BUF3CR 0x1c #define QUADSPI_BUF3CR_ALLMST_MASK BIT(31) #define QUADSPI_BUF3CR_ADATSZ(x) ((x) << 8) @@ -184,6 +189,7 @@ struct fsl_qspi_devtype_data { unsigned int rxfifo; unsigned int txfifo; + int invalid_mstrid; unsigned int ahb_buf_size; unsigned int quirks; bool little_endian; @@ -192,6 +198,7 @@ struct fsl_qspi_devtype_data { static const struct fsl_qspi_devtype_data vybrid_data = { .rxfifo = SZ_128, .txfifo = SZ_64, + .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID, .ahb_buf_size = SZ_1K, .quirks = QUADSPI_QUIRK_SWAP_ENDIAN, .little_endian = true, @@ -200,6 +207,7 @@ static const struct fsl_qspi_devtype_data vybrid_data = { static const struct fsl_qspi_devtype_data imx6sx_data = { .rxfifo = SZ_128, .txfifo = SZ_512, + .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID, .ahb_buf_size = SZ_1K, .quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618, .little_endian = true, @@ -208,6 +216,7 @@ static const struct fsl_qspi_devtype_data imx6sx_data = { static const struct fsl_qspi_devtype_data imx7d_data = { .rxfifo = SZ_128, .txfifo = SZ_512, + .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID, .ahb_buf_size = SZ_1K, .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK, .little_endian = true, @@ -216,6 +225,7 @@ static const struct fsl_qspi_devtype_data imx7d_data = { static const struct fsl_qspi_devtype_data imx6ul_data = { .rxfifo = SZ_128, .txfifo = SZ_512, + .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID, .ahb_buf_size = SZ_1K, .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK, .little_endian = true, @@ -224,6 +234,7 @@ static const struct fsl_qspi_devtype_data imx6ul_data = { static const struct fsl_qspi_devtype_data ls1021a_data = { .rxfifo = SZ_128, .txfifo = SZ_64, + .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID, .ahb_buf_size = SZ_1K, .quirks = 0, .little_endian = false, @@ -233,6 +244,7 @@ static const struct fsl_qspi_devtype_data ls2080a_data = { .rxfifo = SZ_128, .txfifo = SZ_64, .ahb_buf_size = SZ_1K, + .invalid_mstrid = 0x0, .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL, .little_endian = true, }; @@ -615,6 +627,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) void __iomem *base = q->iobase; u32 addr_offset = 0; int err = 0; + int invalid_mstrid = q->devtype_data->invalid_mstrid; mutex_lock(&q->lock); @@ -638,6 +651,10 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC | QUADSPI_SPTRCLR_IPPTRC, base + QUADSPI_SPTRCLR); + qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF0CR); + qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF1CR); + qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF2CR); + fsl_qspi_prepare_lut(q, op); /* -- cgit From 8f5c285f3ef5ab3c7cf5288d63bdaa3549be2118 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 1 Oct 2019 11:14:05 +0300 Subject: SPI: designware: pci: Switch over to MSI interrupts Some devices support MSI interrupts. Let's at least try to use them in platforms that provide MSI capability. Signed-off-by: Felipe Balbi Link: https://lore.kernel.org/r/20191001081405.764161-1-felipe.balbi@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 140644913e6c..7ab53f4d04b9 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -57,13 +57,18 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Get basic io resource and map it */ dws->paddr = pci_resource_start(pdev, pci_bar); + pci_set_master(pdev); ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev)); if (ret) return ret; + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + dws->regs = pcim_iomap_table(pdev)[pci_bar]; - dws->irq = pdev->irq; + dws->irq = pci_irq_vector(pdev, 0); /* * Specific handling for platforms, like dma setup, @@ -80,12 +85,15 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; } } else { + pci_free_irq_vectors(pdev); return -ENODEV; } ret = dw_spi_add_host(&pdev->dev, dws); - if (ret) + if (ret) { + pci_free_irq_vectors(pdev); return ret; + } /* PCI hook and SPI hook use the same drv data */ pci_set_drvdata(pdev, dws); @@ -101,6 +109,7 @@ static void spi_pci_remove(struct pci_dev *pdev) struct dw_spi *dws = pci_get_drvdata(pdev); dw_spi_remove_host(dws); + pci_free_irq_vectors(pdev); } #ifdef CONFIG_PM_SLEEP -- cgit From 3c0f9d8bcf47ed33f479cf9dc933d405020aefe4 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 1 Oct 2019 23:52:16 +0300 Subject: spi: spi-fsl-dspi: Always use the TCFQ devices in poll mode With this patch, the "interrupts" property from the device tree bindings is ignored, even if present, if the driver runs in TCFQ mode. Switching to using the DSPI in poll mode has several distinct benefits: - With interrupts, the DSPI driver in TCFQ mode raises an IRQ after each transmitted word. There is more time wasted for the "waitq" event than for actual I/O. And the DSPI IRQ count can easily get the largest in /proc/interrupts on Freescale boards with attached SPI devices. - The SPI I/O time is both lower, and more consistently so. Attached to some Freescale devices are either PTP switches, or SPI RTCs. For reading time off of a SPI slave device, it is important that all SPI transfers take a deterministic time to complete. - In poll mode there is much less time spent by the CPU in hardirq context, which helps with the response latency of the system, and at the same time there is more control over when interrupts must be disabled (to get a precise timestamp measurement, which will come in a future patch): win-win. On the LS1021A-TSN board, where the SPI device is a SJA1105 PTP switch (with a bits_per_word=8 driver), I created a "benchmark" where I periodically transferred a 12-byte message once per second, for 120 seconds. I then recorded the time before putting the first byte in the TX FIFO, and the time after reading the last byte from the RX FIFO. That is the transfer delay in nanoseconds. Interrupt mode: delay: min 125120 max 168320 mean 150286 std dev 17675.3 Poll mode: delay: min 69440 max 119040 mean 70312.9 std dev 8065.34 Both the mean latency and the standard deviation are more than 50% lower in poll mode than in interrupt mode, and the 'max' in poll mode is lower than the 'min' in interrupt mode. This is with an 'ondemand' governor on an otherwise idle system - therefore running mostly at 600 MHz out of a max of 1200 MHz. Signed-off-by: Vladimir Oltean Link: https://lore.kernel.org/r/20191001205216.32115-1-olteanv@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 2c0f211eed87..c61074502145 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -707,7 +707,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) regmap_read(dspi->regmap, SPI_SR, &spi_sr); regmap_write(dspi->regmap, SPI_SR, spi_sr); - if (!(spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF))) + if (!(spi_sr & SPI_SR_EOQF)) return IRQ_NONE; if (dspi_rxtx(dspi) == 0) { @@ -1134,6 +1134,9 @@ static int dspi_probe(struct platform_device *pdev) dspi_init(dspi); + if (dspi->devtype_data->trans_mode == DSPI_TCFQ_MODE) + goto poll_mode; + dspi->irq = platform_get_irq(pdev, 0); if (dspi->irq <= 0) { dev_info(&pdev->dev, -- cgit From 62217f8b084a05dd2d84781a8ca065098df21ec7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 4 Oct 2019 14:43:32 -0700 Subject: spi: gpio: Look for a device node instead of match This driver doesn't do anything with the match for the device node. The logic is the same as looking to see if a device node exists or not because this driver wouldn't probe unless there is a device node match when the device is created from DT. Just test for the presence of the device node to simplify and avoid referencing a potentially undefined match table when CONFIG_OF=n. Cc: Arnd Bergmann Cc: Geert Uytterhoeven Cc: Mark Brown Cc: Rob Herring Cc: Frank Rowand Cc: Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20191004214334.149976-9-swboyd@chromium.org Signed-off-by: Mark Brown --- drivers/spi/spi-gpio.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 1d3e23ec20a6..42f4d82e9c5a 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -362,9 +362,6 @@ static int spi_gpio_probe(struct platform_device *pdev) struct spi_gpio *spi_gpio; struct device *dev = &pdev->dev; struct spi_bitbang *bb; - const struct of_device_id *of_id; - - of_id = of_match_device(spi_gpio_dt_ids, &pdev->dev); master = spi_alloc_master(dev, sizeof(*spi_gpio)); if (!master) @@ -374,7 +371,7 @@ static int spi_gpio_probe(struct platform_device *pdev) if (status) return status; - if (of_id) + if (pdev->dev.of_node) status = spi_gpio_probe_dt(pdev, master); else status = spi_gpio_probe_pdata(pdev, master); -- cgit From b42faeee718ce13ef6eb99c24880b58deb54c8fa Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 5 Sep 2019 04:01:12 +0300 Subject: spi: Add a PTP system timestamp to the transfer structure SPI is one of the interfaces used to access devices which have a POSIX clock driver (real time clocks, 1588 timers etc). The fact that the SPI bus is slow is not what the main problem is, but rather the fact that drivers don't take a constant amount of time in transferring data over SPI. When there is a high delay in the readout of time, there will be uncertainty in the value that has been read out of the peripheral. When that delay is constant, the uncertainty can at least be approximated with a certain accuracy which is fine more often than not. Timing jitter occurs all over in the kernel code, and is mainly caused by having to let go of the CPU for various reasons such as preemption, servicing interrupts, going to sleep, etc. Another major reason is CPU dynamic frequency scaling. It turns out that the problem of retrieving time from a SPI peripheral with high accuracy can be solved by the use of "PTP system timestamping" - a mechanism to correlate the time when the device has snapshotted its internal time counter with the Linux system time at that same moment. This is sufficient for having a precise time measurement - it is not necessary for the whole SPI transfer to be transmitted "as fast as possible", or "as low-jitter as possible". The system has to be low-jitter for a very short amount of time to be effective. This patch introduces a PTP system timestamping mechanism in struct spi_transfer. This is to be used by SPI device drivers when they need to know the exact time at which the underlying device's time was snapshotted. More often than not, SPI peripherals have a very exact timing for when their SPI-to-interconnect bridge issues a transaction for snapshotting and reading the time register, and that will be dependent on when the SPI-to-interconnect bridge figures out that this is what it should do, aka as soon as it sees byte N of the SPI transfer. Since spi_device drivers are the ones who'd know best how the peripheral behaves in this regard, expose a mechanism in spi_transfer which allows them to specify which word (or word range) from the transfer should be timestamped. Add a default implementation of the PTP system timestamping in the SPI core. This is not going to be satisfactory performance-wise, but should at least increase the likelihood that SPI device drivers will use PTP system timestamping in the future. There are 3 entry points from the core towards the SPI controller drivers: - transfer_one: The driver is passed individual spi_transfers to execute. This is the easiest to timestamp. - transfer_one_message: The core passes the driver an entire spi_message (a potential batch of spi_transfers). The core puts the same pre and post timestamp to all transfers within a message. This is not ideal, but nothing better can be done by default anyway, since the core has no insight into how the driver batches the transfers. - transfer: Like transfer_one_message, but for unqueued drivers (i.e. the driver implements its own queue scheduling). Signed-off-by: Vladimir Oltean Link: https://lore.kernel.org/r/20190905010114.26718-3-olteanv@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f9502dbbb5c1..9bb36c32cbf9 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1171,6 +1171,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, spi_statistics_add_transfer_stats(statm, xfer, ctlr); spi_statistics_add_transfer_stats(stats, xfer, ctlr); + if (!ctlr->ptp_sts_supported) { + xfer->ptp_sts_word_pre = 0; + ptp_read_system_prets(xfer->ptp_sts); + } + if (xfer->tx_buf || xfer->rx_buf) { reinit_completion(&ctlr->xfer_completion); @@ -1197,6 +1202,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, xfer->len); } + if (!ctlr->ptp_sts_supported) { + ptp_read_system_postts(xfer->ptp_sts); + xfer->ptp_sts_word_post = xfer->len; + } + trace_spi_transfer_stop(msg, xfer); if (msg->status != -EINPROGRESS) @@ -1265,6 +1275,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); */ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) { + struct spi_transfer *xfer; struct spi_message *msg; bool was_busy = false; unsigned long flags; @@ -1391,6 +1402,13 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) goto out; } + if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) { + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + xfer->ptp_sts_word_pre = 0; + ptp_read_system_prets(xfer->ptp_sts); + } + } + ret = ctlr->transfer_one_message(ctlr, msg); if (ret) { dev_err(&ctlr->dev, @@ -1418,6 +1436,99 @@ static void spi_pump_messages(struct kthread_work *work) __spi_pump_messages(ctlr, true); } +/** + * spi_take_timestamp_pre - helper for drivers to collect the beginning of the + * TX timestamp for the requested byte from the SPI + * transfer. The frequency with which this function + * must be called (once per word, once for the whole + * transfer, once per batch of words etc) is arbitrary + * as long as the @tx buffer offset is greater than or + * equal to the requested byte at the time of the + * call. The timestamp is only taken once, at the + * first such call. It is assumed that the driver + * advances its @tx buffer pointer monotonically. + * @ctlr: Pointer to the spi_controller structure of the driver + * @xfer: Pointer to the transfer being timestamped + * @tx: Pointer to the current word within the xfer->tx_buf that the driver is + * preparing to transmit right now. + * @irqs_off: If true, will disable IRQs and preemption for the duration of the + * transfer, for less jitter in time measurement. Only compatible + * with PIO drivers. If true, must follow up with + * spi_take_timestamp_post or otherwise system will crash. + * WARNING: for fully predictable results, the CPU frequency must + * also be under control (governor). + */ +void spi_take_timestamp_pre(struct spi_controller *ctlr, + struct spi_transfer *xfer, + const void *tx, bool irqs_off) +{ + u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8); + + if (!xfer->ptp_sts) + return; + + if (xfer->timestamped_pre) + return; + + if (tx < (xfer->tx_buf + xfer->ptp_sts_word_pre * bytes_per_word)) + return; + + /* Capture the resolution of the timestamp */ + xfer->ptp_sts_word_pre = (tx - xfer->tx_buf) / bytes_per_word; + + xfer->timestamped_pre = true; + + if (irqs_off) { + local_irq_save(ctlr->irq_flags); + preempt_disable(); + } + + ptp_read_system_prets(xfer->ptp_sts); +} +EXPORT_SYMBOL_GPL(spi_take_timestamp_pre); + +/** + * spi_take_timestamp_post - helper for drivers to collect the end of the + * TX timestamp for the requested byte from the SPI + * transfer. Can be called with an arbitrary + * frequency: only the first call where @tx exceeds + * or is equal to the requested word will be + * timestamped. + * @ctlr: Pointer to the spi_controller structure of the driver + * @xfer: Pointer to the transfer being timestamped + * @tx: Pointer to the current word within the xfer->tx_buf that the driver has + * just transmitted. + * @irqs_off: If true, will re-enable IRQs and preemption for the local CPU. + */ +void spi_take_timestamp_post(struct spi_controller *ctlr, + struct spi_transfer *xfer, + const void *tx, bool irqs_off) +{ + u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8); + + if (!xfer->ptp_sts) + return; + + if (xfer->timestamped_post) + return; + + if (tx < (xfer->tx_buf + xfer->ptp_sts_word_post * bytes_per_word)) + return; + + ptp_read_system_postts(xfer->ptp_sts); + + if (irqs_off) { + local_irq_restore(ctlr->irq_flags); + preempt_enable(); + } + + /* Capture the resolution of the timestamp */ + xfer->ptp_sts_word_post = (tx - xfer->tx_buf) / bytes_per_word; + + xfer->timestamped_post = true; +} +EXPORT_SYMBOL_GPL(spi_take_timestamp_post); + /** * spi_set_thread_rt - set the controller to pump at realtime priority * @ctlr: controller to boost priority of @@ -1503,6 +1614,7 @@ EXPORT_SYMBOL_GPL(spi_get_next_queued_message); */ void spi_finalize_current_message(struct spi_controller *ctlr) { + struct spi_transfer *xfer; struct spi_message *mesg; unsigned long flags; int ret; @@ -1511,6 +1623,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr) mesg = ctlr->cur_msg; spin_unlock_irqrestore(&ctlr->queue_lock, flags); + if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) { + list_for_each_entry(xfer, &mesg->transfers, transfer_list) { + ptp_read_system_postts(xfer->ptp_sts); + xfer->ptp_sts_word_post = xfer->len; + } + } + spi_unmap_msg(ctlr, mesg); if (ctlr->cur_msg_prepared && ctlr->unprepare_message) { @@ -3273,6 +3392,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) static int __spi_async(struct spi_device *spi, struct spi_message *message) { struct spi_controller *ctlr = spi->controller; + struct spi_transfer *xfer; /* * Some controllers do not support doing regular SPI transfers. Return @@ -3288,6 +3408,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) trace_spi_message_submit(message); + if (!ctlr->ptp_sts_supported) { + list_for_each_entry(xfer, &message->transfers, transfer_list) { + xfer->ptp_sts_word_pre = 0; + ptp_read_system_prets(xfer->ptp_sts); + } + } + return ctlr->transfer(spi, message); } -- cgit From d6b71dfaeeba115dd61a7f367cf04c2d0ca77ebb Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 5 Sep 2019 04:01:13 +0300 Subject: spi: spi-fsl-dspi: Implement the PTP system timestamping for TCFQ mode In this mode, the DSPI controller uses PIO to transfer word by word. In comparison, in EOQ mode the 4-word deep FIFO is being used, hence the current logic will need some adaptation for which I do not have the hardware (Coldfire) to test. It is not clear what is the timing of DMA transfers and whether timestamping in the driver brings any overall performance increase compared to regular timestamping done in the core. Short phc2sys summary after 58 minutes of running on LS1021A-TSN with interrupts disabled during the critical section: offset: min -26251 max 16416 mean -21.8672 std dev 863.416 delay: min 4720 max 57280 mean 5182.49 std dev 1607.19 lost servo lock 3 times Summary of the same phc2sys service running for 120 minutes with interrupts disabled: offset: min -378 max 381 mean -0.0083089 std dev 101.495 delay: min 4720 max 5920 mean 5129.38 std dev 154.899 lost servo lock 0 times The minimum delay (pre to post time) in nanoseconds is the same, but the maximum delay is quite a bit higher, due to interrupts getting sometimes executed and interfering with the measurement. Hence set disable_irqs whenever possible (aka when the driver runs in poll mode - otherwise it would be a contradiction in terms). Signed-off-by: Vladimir Oltean Link: https://lore.kernel.org/r/20190905010114.26718-4-olteanv@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index c61074502145..c0e96cc7fc51 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -129,6 +129,7 @@ enum dspi_trans_mode { struct fsl_dspi_devtype_data { enum dspi_trans_mode trans_mode; u8 max_clock_factor; + bool ptp_sts_supported; bool xspi_mode; }; @@ -140,12 +141,14 @@ static const struct fsl_dspi_devtype_data vf610_data = { static const struct fsl_dspi_devtype_data ls1021a_v1_data = { .trans_mode = DSPI_TCFQ_MODE, .max_clock_factor = 8, + .ptp_sts_supported = true, .xspi_mode = true, }; static const struct fsl_dspi_devtype_data ls2085a_data = { .trans_mode = DSPI_TCFQ_MODE, .max_clock_factor = 8, + .ptp_sts_supported = true, }; static const struct fsl_dspi_devtype_data coldfire_data = { @@ -654,6 +657,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi) u16 spi_tcnt; u32 spi_tcr; + spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer, + dspi->tx - dspi->bytes_per_word, !dspi->irq); + /* Get transfer counter (in number of SPI transfers). It was * reset to 0 when transfer(s) were started. */ @@ -672,6 +678,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi) /* Success! */ return 0; + spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, + dspi->tx, !dspi->irq); + if (trans_mode == DSPI_EOQ_MODE) dspi_eoq_write(dspi); else if (trans_mode == DSPI_TCFQ_MODE) @@ -779,6 +788,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, SPI_FRAME_EBITS(transfer->bits_per_word) | SPI_CTARE_DTCP(1)); + spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, + dspi->tx, !dspi->irq); + trans_mode = dspi->devtype_data->trans_mode; switch (trans_mode) { case DSPI_EOQ_MODE: @@ -1155,6 +1167,7 @@ static int dspi_probe(struct platform_device *pdev) init_waitqueue_head(&dspi->waitq); poll_mode: + if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { ret = dspi_request_dma(dspi, res->start); if (ret < 0) { @@ -1166,6 +1179,8 @@ poll_mode: ctlr->max_speed_hz = clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor; + ctlr->ptp_sts_supported = dspi->devtype_data->ptp_sts_supported; + platform_set_drvdata(pdev, ctlr); ret = spi_register_controller(ctlr); -- cgit From 944be39bd47cf0d45e50eb45b487031dde8569e5 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Wed, 9 Oct 2019 08:37:16 +0800 Subject: spi: omap-100k: Remove set but not used variable 'dataH' Fixes gcc '-Wunused-but-set-variable' warning: drivers/spi/spi-omap-100k.c: In function spi100k_read_data: drivers/spi/spi-omap-100k.c:140:6: warning: variable dataH set but not used [-Wunused-but-set-variable] It is not used since commit 35c9049b2704 ("Add OMAP spi100k driver") Reported-by: Hulk Robot Signed-off-by: zhengbin Link: https://lore.kernel.org/r/1570581437-104549-2-git-send-email-zhengbin13@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index b955ca8796d2..43a4785fc89b 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -128,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) static int spi100k_read_data(struct spi_master *master, int len) { - int dataH, dataL; + int dataL; struct omap1_spi100k *spi100k = spi_master_get_devdata(master); /* Always do at least 16 bits */ @@ -146,7 +146,7 @@ static int spi100k_read_data(struct spi_master *master, int len) udelay(1000); dataL = readw(spi100k->base + SPI_RX_LSB); - dataH = readw(spi100k->base + SPI_RX_MSB); + readw(spi100k->base + SPI_RX_MSB); spi100k_disable_clock(master); return dataL; -- cgit From c46652ee6cacc42513e4f555f0050db2d537dab6 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Wed, 9 Oct 2019 08:37:17 +0800 Subject: spi: npcm: Remove set but not used variable 'val' Fixes gcc '-Wunused-but-set-variable' warning: drivers/spi/spi-npcm-pspi.c: In function npcm_pspi_handler: drivers/spi/spi-npcm-pspi.c:296:6: warning: variable val set but not used [-Wunused-but-set-variable] It is not used since commit 2a22f1b30cee ("spi: npcm: add NPCM PSPI controller driver") Reported-by: Hulk Robot Signed-off-by: zhengbin Link: https://lore.kernel.org/r/1570581437-104549-3-git-send-email-zhengbin13@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-pspi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index b191d57d1dc0..fe624731c74c 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -293,7 +293,6 @@ static void npcm_pspi_reset_hw(struct npcm_pspi *priv) static irqreturn_t npcm_pspi_handler(int irq, void *dev_id) { struct npcm_pspi *priv = dev_id; - u16 val; u8 stat; stat = ioread8(priv->base + NPCM_PSPI_STAT); @@ -303,7 +302,7 @@ static irqreturn_t npcm_pspi_handler(int irq, void *dev_id) if (priv->tx_buf) { if (stat & NPCM_PSPI_STAT_RBF) { - val = ioread8(NPCM_PSPI_DATA + priv->base); + ioread8(NPCM_PSPI_DATA + priv->base); if (priv->tx_bytes == 0) { npcm_pspi_disable(priv); complete(&priv->xfer_done); -- cgit From 6b3f236a998550dba91a46a22feb1cc02f39fb06 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:29 +0300 Subject: spi: move `cs_change_delay` backwards compat logic outside switch The `cs_change_delay` backwards compatibility value could be moved outside of the switch statement. The only reason to do it, is to make the next patches easier to diff. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-2-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9bb36c32cbf9..7ba981cdb86b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1114,16 +1114,15 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg, u32 hz; /* return early on "fast" mode - for everything but USECS */ - if (!delay && unit != SPI_DELAY_UNIT_USECS) + if (!delay) { + if (unit == SPI_DELAY_UNIT_USECS) + _spi_transfer_delay_ns(10000); return; + } switch (unit) { case SPI_DELAY_UNIT_USECS: - /* for compatibility use default of 10us */ - if (!delay) - delay = 10000; - else - delay *= 1000; + delay *= 1000; break; case SPI_DELAY_UNIT_NSECS: /* nothing to do here */ break; -- cgit From b2c98153f45fc17b9fcb241000f2d131ddea6030 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:30 +0300 Subject: spi: introduce spi_delay struct as "value + unit" & spi_delay_exec() There are plenty of delays that have been introduced in SPI core. Most of them are in micro-seconds, some need to be in nano-seconds, and some in clock-cycles. For some of these delays (related to transfers & CS timing) it may make sense to have a `spi_delay` struct that abstracts these a bit. The important element of these delays [for unification] seems to be the `unit` of the delay. It looks like micro-seconds is good enough for most people, but every-once in a while, some delays seem to require other units of measurement. This change adds the `spi_delay` struct & a `spi_delay_exec()` function that processes a `spi_delay` object/struct to execute the delay. It's a copy of the `cs_change_delay` mechanism, but without the default for 10 uS. The clock-cycle delay unit is a bit special, as it needs to be bound to an `spi_transfer` object to execute. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-3-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7ba981cdb86b..7499a4efbaba 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1106,6 +1106,57 @@ static void _spi_transfer_delay_ns(u32 ns) } } +static int _spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer) +{ + u32 delay = _delay->value; + u32 unit = _delay->unit; + u32 hz; + + if (!delay) + return 0; + + switch (unit) { + case SPI_DELAY_UNIT_USECS: + delay *= 1000; + break; + case SPI_DELAY_UNIT_NSECS: /* nothing to do here */ + break; + case SPI_DELAY_UNIT_SCK: + /* clock cycles need to be obtained from spi_transfer */ + if (!xfer) + return -EINVAL; + /* if there is no effective speed know, then approximate + * by underestimating with half the requested hz + */ + hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2; + if (!hz) + return -EINVAL; + delay *= DIV_ROUND_UP(1000000000, hz); + break; + default: + return -EINVAL; + } + + return delay; +} + +int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer) +{ + int delay; + + if (!_delay) + return -EINVAL; + + delay = _spi_delay_to_ns(_delay, xfer); + if (delay < 0) + return delay; + + _spi_transfer_delay_ns(delay); + + return 0; +} +EXPORT_SYMBOL_GPL(spi_delay_exec); + static void _spi_transfer_cs_change_delay(struct spi_message *msg, struct spi_transfer *xfer) { -- cgit From 329f0dac4cad9fa4b1439a88180d91bcb5c4eaf8 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:31 +0300 Subject: spi: make `cs_change_delay` the first user of the `spi_delay` logic Since the logic for `spi_delay` struct + `spi_delay_exec()` has been copied from the `cs_change_delay` logic, it's natural to make this delay, the first user. The `cs_change_delay` logic requires that the default remain 10 uS, in case it is unspecified/unconfigured. So, there is some special handling needed to do that. The ADIS library is one of the few users of the new `cs_change_delay` parameter for an spi_transfer. The introduction of the `spi_delay` struct, requires that the users of of `cs_change_delay` get an update. This change also updates the ADIS library. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-4-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7499a4efbaba..b69c14082c52 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1160,9 +1160,9 @@ EXPORT_SYMBOL_GPL(spi_delay_exec); static void _spi_transfer_cs_change_delay(struct spi_message *msg, struct spi_transfer *xfer) { - u32 delay = xfer->cs_change_delay; - u32 unit = xfer->cs_change_delay_unit; - u32 hz; + u32 delay = xfer->cs_change_delay.value; + u32 unit = xfer->cs_change_delay.unit; + int ret; /* return early on "fast" mode - for everything but USECS */ if (!delay) { @@ -1171,27 +1171,13 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg, return; } - switch (unit) { - case SPI_DELAY_UNIT_USECS: - delay *= 1000; - break; - case SPI_DELAY_UNIT_NSECS: /* nothing to do here */ - break; - case SPI_DELAY_UNIT_SCK: - /* if there is no effective speed know, then approximate - * by underestimating with half the requested hz - */ - hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2; - delay *= DIV_ROUND_UP(1000000000, hz); - break; - default: + ret = spi_delay_exec(&xfer->cs_change_delay, xfer); + if (ret) { dev_err_once(&msg->spi->dev, "Use of unsupported delay unit %i, using default of 10us\n", - xfer->cs_change_delay_unit); - delay = 10000; + unit); + _spi_transfer_delay_ns(10000); } - /* now sleep for the requested amount of time */ - _spi_transfer_delay_ns(delay); } /* -- cgit From 84593a131c3af21d686d05c4b4432290a415d399 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:32 +0300 Subject: spi: sprd: convert transfer word delay to spi_delay struct The Spreadtrum SPI driver is the only user of the `word_delay` field in the `spi_transfer` struct. This change converts the field to use the `spi_delay` struct. This also enforces the users to specify the delay unit to be `SPI_DELAY_UNIT_SCK`. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-5-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-sprd.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index 8c9021b7f7a9..2ee1feb41681 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -669,11 +669,15 @@ static void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz) writel_relaxed(clk_div, ss->base + SPRD_SPI_CLKD); } -static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t) +static int sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t) { + struct spi_delay *d = &t->word_delay; u16 word_delay, interval; u32 val; + if (d->unit != SPI_DELAY_UNIT_SCK) + return -EINVAL; + val = readl_relaxed(ss->base + SPRD_SPI_CTL7); val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX); /* Set default chip selection, clock phase and clock polarity */ @@ -686,7 +690,7 @@ static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t) * formula as below per datasheet: * interval time (source clock cycles) = interval * 4 + 10. */ - word_delay = clamp_t(u16, t->word_delay, SPRD_SPI_MIN_DELAY_CYCLE, + word_delay = clamp_t(u16, d->value, SPRD_SPI_MIN_DELAY_CYCLE, SPRD_SPI_MAX_DELAY_CYCLE); interval = DIV_ROUND_UP(word_delay - 10, 4); ss->word_delay = interval * 4 + 10; @@ -711,6 +715,8 @@ static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t) val &= ~SPRD_SPI_DATA_LINE2_EN; writel_relaxed(val, ss->base + SPRD_SPI_CTL7); + + return 0; } static int sprd_spi_setup_transfer(struct spi_device *sdev, @@ -719,13 +725,16 @@ static int sprd_spi_setup_transfer(struct spi_device *sdev, struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); u8 bits_per_word = t->bits_per_word; u32 val, mode = 0; + int ret; ss->len = t->len; ss->tx_buf = t->tx_buf; ss->rx_buf = t->rx_buf; ss->hw_mode = sdev->mode; - sprd_spi_init_hw(ss, t); + ret = sprd_spi_init_hw(ss, t); + if (ret) + return ret; /* Set tansfer speed and valid bits */ sprd_spi_set_speed(ss, t->speed_hz); -- cgit From 21e26062052c60d31640e614b792473fca787f9f Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:33 +0300 Subject: spi: orion: use new `word_delay` field for SPI transfers The `word_delay` field had it's type changed to `struct spi_delay`. This allows users to specify nano-second or clock-cycle delays (if needed). Converting to use `word_delay` is straightforward: it just uses the new `spi_delay_exec()` routine, that handles the `unit` part. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-6-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 81c991c4ddbf..c7266ef295fd 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -467,8 +467,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0) goto out; count--; - if (xfer->word_delay_usecs) - udelay(xfer->word_delay_usecs); + spi_delay_exec(&xfer->word_delay, xfer); } while (count); } else if (word_len == 16) { const u16 *tx = xfer->tx_buf; @@ -478,8 +477,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0) goto out; count -= 2; - if (xfer->word_delay_usecs) - udelay(xfer->word_delay_usecs); + spi_delay_exec(&xfer->word_delay, xfer); } while (count); } -- cgit From ec3fa72fa8404128771a095d5a56b738752ba9ff Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:34 +0300 Subject: spi: spidev: use new `word_delay` field for spi transfers The `word_delay` field had it's type changed to `struct spi_delay`. This allows users to specify nano-second or clock-cycle delays (if needed). Converting to use `word_delay` is straightforward: it's just assigning the value to `word_delay.value` and hard-coding the `word_delay.unit` to `SPI_DELAY_UNIT_USECS` This keeps the uapi for spidev un-changed. Changing it can be part of another changeset and discussion. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-7-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 3ea9d8a3e6e8..d63235dcb231 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -267,7 +267,8 @@ static int spidev_message(struct spidev_data *spidev, k_tmp->bits_per_word = u_tmp->bits_per_word; k_tmp->delay_usecs = u_tmp->delay_usecs; k_tmp->speed_hz = u_tmp->speed_hz; - k_tmp->word_delay_usecs = u_tmp->word_delay_usecs; + k_tmp->word_delay.value = u_tmp->word_delay_usecs; + k_tmp->word_delay.unit = SPI_DELAY_UNIT_USECS; if (!k_tmp->speed_hz) k_tmp->speed_hz = spidev->speed_hz; #ifdef VERBOSE -- cgit From 6c613f68aabf33385c01e949204ac5ed30887161 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:35 +0300 Subject: spi: core,atmel: convert `word_delay_usecs` -> `word_delay` for spi_device This change does a conversion from the `word_delay_usecs` -> `word_delay` for the `spi_device` struct. This allows users to specify inter-word delays in other unit types (nano-seconds or clock cycles), depending on how users want. The Atmel SPI driver is the only current user of the `word_delay_usecs` field (from the `spi_device` struct). So, it needed a slight conversion to use the `word_delay` as an `spi_delay` struct. In SPI core, the only required mechanism is to update the `word_delay` information per `spi_transfer`. This requires a bit more logic than before, because it needs that both delays be converted to a common unit (nano-seconds) for comparison. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-8-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 26 ++++++++++++++++++++++++-- drivers/spi/spi.c | 24 ++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 3ed5e663da6f..1471b049f99a 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1149,12 +1149,31 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id) return ret; } +static int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as) +{ + struct spi_delay *delay = &spi->word_delay; + u32 value = delay->value; + + switch (delay->unit) { + case SPI_DELAY_UNIT_NSECS: + value /= 1000; + break; + case SPI_DELAY_UNIT_USECS: + break; + default: + return -EINVAL; + } + + return (as->spi_clk / 1000000 * value) >> 5; +} + static int atmel_spi_setup(struct spi_device *spi) { struct atmel_spi *as; struct atmel_spi_device *asd; u32 csr; unsigned int bits = spi->bits_per_word; + int word_delay_csr; as = spi_master_get_devdata(spi->master); @@ -1178,11 +1197,14 @@ static int atmel_spi_setup(struct spi_device *spi) */ csr |= SPI_BF(DLYBS, 0); + word_delay_csr = atmel_word_delay_csr(spi, as); + if (word_delay_csr < 0) + return word_delay_csr; + /* DLYBCT adds delays between words. This is useful for slow devices * that need a bit of time to setup the next transfer. */ - csr |= SPI_BF(DLYBCT, - (as->spi_clk / 1000000 * spi->word_delay_usecs) >> 5); + csr |= SPI_BF(DLYBCT, word_delay_csr); asd = spi->controller_state; if (!asd) { diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b69c14082c52..307e440dd92d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3281,6 +3281,26 @@ void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold, } EXPORT_SYMBOL_GPL(spi_set_cs_timing); +static int _spi_xfer_word_delay_update(struct spi_transfer *xfer, + struct spi_device *spi) +{ + int delay1, delay2; + + delay1 = _spi_delay_to_ns(&xfer->word_delay, xfer); + if (delay1 < 0) + return delay1; + + delay2 = _spi_delay_to_ns(&spi->word_delay, xfer); + if (delay2 < 0) + return delay2; + + if (delay1 < delay2) + memcpy(&xfer->word_delay, &spi->word_delay, + sizeof(xfer->word_delay)); + + return 0; +} + static int __spi_validate(struct spi_device *spi, struct spi_message *message) { struct spi_controller *ctlr = spi->controller; @@ -3416,8 +3436,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) return -EINVAL; } - if (xfer->word_delay_usecs < spi->word_delay_usecs) - xfer->word_delay_usecs = spi->word_delay_usecs; + if (_spi_xfer_word_delay_update(xfer, spi)) + return -EINVAL; } message->status = -EINPROGRESS; -- cgit From bebcfd272df648542c458d28fbd6a8f9428b5310 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:36 +0300 Subject: spi: introduce `delay` field for `spi_transfer` + spi_transfer_delay_exec() The change introduces the `delay` field to the `spi_transfer` struct as an `struct spi_delay` type. This intends to eventually replace `delay_usecs`. But, since there are many users of `delay_usecs`, this needs some intermediate work. A helper called `spi_transfer_delay_exec()` is also added, which maintains backwards compatibility with `delay_usecs`, by assigning the value to `delay` if non-zero. This should maintain backwards compatibility with current users of `udelay_usecs`. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-9-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 307e440dd92d..2e448078a117 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1248,8 +1248,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, if (msg->status != -EINPROGRESS) goto out; - if (xfer->delay_usecs) - _spi_transfer_delay_ns(xfer->delay_usecs * 1000); + spi_transfer_delay_exec(xfer); if (xfer->cs_change) { if (list_is_last(&xfer->transfer_list, @@ -3026,10 +3025,11 @@ struct spi_replaced_transfers *spi_replace_transfers( /* add to list */ list_add(&xfer->transfer_list, rxfer->replaced_after); - /* clear cs_change and delay_usecs for all but the last */ + /* clear cs_change and delay for all but the last */ if (i) { xfer->cs_change = false; xfer->delay_usecs = 0; + xfer->delay.value = 0; } } -- cgit From cd13152bce34cd71f560a7c4a8f66096f2445984 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:38 +0300 Subject: spi: tegra114: use `spi_transfer_delay_exec` helper The tegra114 driver has a weird/separate `tegra_spi_transfer_delay()` function that does 2 delays: one mdelay() and one udelay(). This was introduced via commit f4fade12d506e14867a2b0a5e2f7aaf227297d8b ("spi/tegra114: Correct support for cs_change"). There doesn't seem to be a mention in that commit message to suggest a specific need/use-case for having the 2 delay calls. For the most part, udelay() should be sufficient. This change replaces it with the new `spi_transfer_delay_exec()`, which should do the same thing. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-11-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 39374c2edcf3..8133dc49d34f 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -984,17 +984,6 @@ static int tegra_spi_setup(struct spi_device *spi) return 0; } -static void tegra_spi_transfer_delay(int delay) -{ - if (!delay) - return; - - if (delay >= 1000) - mdelay(delay / 1000); - - udelay(delay % 1000); -} - static void tegra_spi_transfer_end(struct spi_device *spi) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); @@ -1098,7 +1087,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, complete_xfer: if (ret < 0 || skip) { tegra_spi_transfer_end(spi); - tegra_spi_transfer_delay(xfer->delay_usecs); + spi_transfer_delay_exec(xfer); goto exit; } else if (list_is_last(&xfer->transfer_list, &msg->transfers)) { @@ -1106,11 +1095,11 @@ complete_xfer: tspi->cs_control = spi; else { tegra_spi_transfer_end(spi); - tegra_spi_transfer_delay(xfer->delay_usecs); + spi_transfer_delay_exec(xfer); } } else if (xfer->cs_change) { tegra_spi_transfer_end(spi); - tegra_spi_transfer_delay(xfer->delay_usecs); + spi_transfer_delay_exec(xfer); } } -- cgit From b883d5eda6c49a807e925b257bf9687d5c351004 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:39 +0300 Subject: spi: tegra20-sflash: use to new `spi_transfer_delay_exec` This conversion to the spi_transfer_delay_exec() helper is not straightforward, as it seems that when a delay is present, the controller issues a command, and then a delay is followed. This change adds support for the new `delay` field which is of type `spi_delay` and keeps backwards compatibility with the old `delay_usecs` field. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-12-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-sflash.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index a841a7250d14..514429379206 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -341,10 +341,11 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master, goto exit; } msg->actual_length += xfer->len; - if (xfer->cs_change && xfer->delay_usecs) { + if (xfer->cs_change && + (xfer->delay_usecs || xfer->delay.value)) { tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND); - udelay(xfer->delay_usecs); + spi_transfer_delay_exec(xfer); } } ret = 0; -- cgit From 867bd8868bbd16e17bbd26c5959abc3118902218 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:40 +0300 Subject: spi: spi-loopback-test: use new `delay` field This change replaces the use of the `delay_usecs` field with the new `delay` field. The code/test still uses micro-seconds, but they are now configured and used via the `struct spi_delay` format of the `delay` field. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-13-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 6f18d4952767..b6d79cd156fb 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -298,12 +298,18 @@ static struct spi_test spi_tests[] = { { .tx_buf = TX(0), .rx_buf = RX(0), - .delay_usecs = 1000, + .delay = { + .value = 1000, + .unit = SPI_DELAY_UNIT_USECS, + }, }, { .tx_buf = TX(0), .rx_buf = RX(0), - .delay_usecs = 1000, + .delay = { + .value = 1000, + .unit = SPI_DELAY_UNIT_USECS, + }, }, }, }, @@ -537,7 +543,7 @@ static int spi_test_check_elapsed_time(struct spi_device *spi, unsigned long long nbits = (unsigned long long)BITS_PER_BYTE * xfer->len; - delay_usecs += xfer->delay_usecs; + delay_usecs += xfer->delay.value; if (!xfer->speed_hz) continue; estimated_time += div_u64(nbits * NSEC_PER_SEC, xfer->speed_hz); -- cgit From 8e319dd5f1ebbc1fffa9e550b2a643cbce7515b1 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:41 +0300 Subject: spi: spidev: use new `delay` field for spi transfers The `delay` field has type `struct spi_delay`. This allows users to specify nano-second or clock-cycle delays (if needed). Converting to use `delay` is straightforward: it's just assigning the value to `delay.value` and hard-coding the `delay.unit` to `SPI_DELAY_UNIT_USECS`. This keeps the uapi for spidev un-changed. Changing it can be part of another changeset and discussion. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-14-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index d63235dcb231..1e217e3e9486 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -265,7 +265,8 @@ static int spidev_message(struct spidev_data *spidev, k_tmp->tx_nbits = u_tmp->tx_nbits; k_tmp->rx_nbits = u_tmp->rx_nbits; k_tmp->bits_per_word = u_tmp->bits_per_word; - k_tmp->delay_usecs = u_tmp->delay_usecs; + k_tmp->delay.value = u_tmp->delay_usecs; + k_tmp->delay.unit = SPI_DELAY_UNIT_USECS; k_tmp->speed_hz = u_tmp->speed_hz; k_tmp->word_delay.value = u_tmp->word_delay_usecs; k_tmp->word_delay.unit = SPI_DELAY_UNIT_USECS; -- cgit From 8105936684681195d9073880b06a123b2e316811 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:42 +0300 Subject: spi: tegra114: change format for `spi_set_cs_timing()` function The initial version of `spi_set_cs_timing()` was implemented with consideration only for clock-cycles as delay. For cases like `CS setup` time, it's sometimes needed that micro-seconds (or nano-seconds) are required, or sometimes even longer delays, for cases where the device needs a little longer to start transferring that after CS is asserted. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-15-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 22 ++++++++++++++++++++-- drivers/spi/spi.c | 16 ++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 8133dc49d34f..e6a450d9b4f0 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -723,15 +723,31 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, dma_release_channel(dma_chan); } -static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly, - u8 hold_dly, u8 inactive_dly) +static int tegra_spi_set_hw_cs_timing(struct spi_device *spi, + struct spi_delay *setup, + struct spi_delay *hold, + struct spi_delay *inactive) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + u8 setup_dly, hold_dly, inactive_dly; u32 setup_hold; u32 spi_cs_timing; u32 inactive_cycles; u8 cs_state; + if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) || + (hold && hold->unit != SPI_DELAY_UNIT_SCK) || + (inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) { + dev_err(&spi->dev, + "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n", + SPI_DELAY_UNIT_SCK); + return -EINVAL; + } + + setup_dly = setup ? setup->value : 0; + hold_dly = hold ? hold->value : 0; + inactive_dly = inactive ? inactive->value : 0; + setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES); hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES); if (setup_dly && hold_dly) { @@ -758,6 +774,8 @@ static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly, tspi->spi_cs_timing2 = spi_cs_timing; tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2); } + + return 0; } static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 2e448078a117..6beeb363515c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3269,15 +3269,19 @@ EXPORT_SYMBOL_GPL(spi_setup); /** * spi_set_cs_timing - configure CS setup, hold, and inactive delays * @spi: the device that requires specific CS timing configuration - * @setup: CS setup time in terms of clock count - * @hold: CS hold time in terms of clock count - * @inactive_dly: CS inactive delay between transfers in terms of clock count + * @setup: CS setup time specified via @spi_delay + * @hold: CS hold time specified via @spi_delay + * @inactive: CS inactive delay between transfers specified via @spi_delay + * + * Return: zero on success, else a negative error code. */ -void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold, - u8 inactive_dly) +int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup, + struct spi_delay *hold, struct spi_delay *inactive) { if (spi->controller->set_cs_timing) - spi->controller->set_cs_timing(spi, setup, hold, inactive_dly); + return spi->controller->set_cs_timing(spi, setup, hold, + inactive); + return -ENOTSUPP; } EXPORT_SYMBOL_GPL(spi_set_cs_timing); -- cgit From 25093bdeb6bcae728e12e3795261dbd3677060a9 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:43 +0300 Subject: spi: implement SW control for CS times This change implements CS control for setup, hold & inactive delays. The `cs_setup` delay is completely new, and can help with cases where asserting the CS, also brings the device out of power-sleep, where there needs to be a longer (than usual), before transferring data. The `cs_hold` time can overlap with the `delay` (or `delay_usecs`) from an SPI transfer. The main difference is that `cs_hold` implies that CS will be de-asserted. The `cs_inactive` delay does not have a clear use-case yet. It has been implemented mostly because the `spi_set_cs_timing()` function implements it. To some degree, this could overlap or replace `cs_change_delay`, but this will require more consideration/investigation in the future. All these delays have been added to the `spi_controller` struct, as they would typically be configured by calling `spi_set_cs_timing()` after an `spi_setup()` call. Software-mode for CS control, implies that the `set_cs_timing()` hook has not been provided for the `spi_controller` object. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-16-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6beeb363515c..21628b0728f1 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -775,6 +775,15 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) static void spi_set_cs(struct spi_device *spi, bool enable) { + bool enable1 = enable; + + if (!spi->controller->set_cs_timing) { + if (enable1) + spi_delay_exec(&spi->controller->cs_setup, NULL); + else + spi_delay_exec(&spi->controller->cs_hold, NULL); + } + if (spi->mode & SPI_CS_HIGH) enable = !enable; @@ -800,6 +809,11 @@ static void spi_set_cs(struct spi_device *spi, bool enable) } else if (spi->controller->set_cs) { spi->controller->set_cs(spi, !enable); } + + if (!spi->controller->set_cs_timing) { + if (!enable1) + spi_delay_exec(&spi->controller->cs_inactive, NULL); + } } #ifdef CONFIG_HAS_DMA @@ -3278,10 +3292,39 @@ EXPORT_SYMBOL_GPL(spi_setup); int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup, struct spi_delay *hold, struct spi_delay *inactive) { + size_t len; + if (spi->controller->set_cs_timing) return spi->controller->set_cs_timing(spi, setup, hold, inactive); - return -ENOTSUPP; + + if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) || + (hold && hold->unit == SPI_DELAY_UNIT_SCK) || + (inactive && inactive->unit == SPI_DELAY_UNIT_SCK)) { + dev_err(&spi->dev, + "Clock-cycle delays for CS not supported in SW mode\n"); + return -ENOTSUPP; + } + + len = sizeof(struct spi_delay); + + /* copy delays to controller */ + if (setup) + memcpy(&spi->controller->cs_setup, setup, len); + else + memset(&spi->controller->cs_setup, 0, len); + + if (hold) + memcpy(&spi->controller->cs_hold, hold, len); + else + memset(&spi->controller->cs_hold, 0, len); + + if (inactive) + memcpy(&spi->controller->cs_inactive, inactive, len); + else + memset(&spi->controller->cs_inactive, 0, len); + + return 0; } EXPORT_SYMBOL_GPL(spi_set_cs_timing); -- cgit From 3984d39b0e41ac4de8b4530ae3911ccf52ed4bbf Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:44 +0300 Subject: spi: spi-fsl-espi: convert transfer delay to `spi_delay` format The way the max delay is computed for this controller, it looks like it is searching for the max delay from an SPI message a using that. No idea if this is valid. But this change should support both `delay_usecs` and the new `delay` data which is of `spi_delay` type. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-17-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 16 +++++++++++++--- drivers/spi/spi.c | 9 +++++---- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index f20326714b9d..f72daf66f3f3 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -437,6 +437,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { unsigned int delay_usecs = 0, rx_nbits = 0; + unsigned int delay_nsecs = 0, delay_nsecs1 = 0; struct spi_transfer *t, trans = {}; int ret; @@ -445,8 +446,16 @@ static int fsl_espi_do_one_msg(struct spi_master *master, goto out; list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->delay_usecs > delay_usecs) - delay_usecs = t->delay_usecs; + if (t->delay_usecs) { + if (t->delay_usecs > delay_usecs) { + delay_usecs = t->delay_usecs; + delay_nsecs = delay_usecs * 1000; + } + } else { + delay_nsecs1 = spi_delay_to_ns(&t->delay, t); + if (delay_nsecs1 > delay_nsecs) + delay_nsecs = delay_nsecs1; + } if (t->rx_nbits > rx_nbits) rx_nbits = t->rx_nbits; } @@ -457,7 +466,8 @@ static int fsl_espi_do_one_msg(struct spi_master *master, trans.len = m->frame_length; trans.speed_hz = t->speed_hz; trans.bits_per_word = t->bits_per_word; - trans.delay_usecs = delay_usecs; + trans.delay.value = delay_nsecs; + trans.delay.unit = SPI_DELAY_UNIT_NSECS; trans.rx_nbits = rx_nbits; if (trans.len) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 21628b0728f1..5414a10afd65 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1120,7 +1120,7 @@ static void _spi_transfer_delay_ns(u32 ns) } } -static int _spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer) +int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer) { u32 delay = _delay->value; u32 unit = _delay->unit; @@ -1153,6 +1153,7 @@ static int _spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer) return delay; } +EXPORT_SYMBOL_GPL(spi_delay_to_ns); int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer) { @@ -1161,7 +1162,7 @@ int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer) if (!_delay) return -EINVAL; - delay = _spi_delay_to_ns(_delay, xfer); + delay = spi_delay_to_ns(_delay, xfer); if (delay < 0) return delay; @@ -3333,11 +3334,11 @@ static int _spi_xfer_word_delay_update(struct spi_transfer *xfer, { int delay1, delay2; - delay1 = _spi_delay_to_ns(&xfer->word_delay, xfer); + delay1 = spi_delay_to_ns(&xfer->word_delay, xfer); if (delay1 < 0) return delay1; - delay2 = _spi_delay_to_ns(&spi->word_delay, xfer); + delay2 = spi_delay_to_ns(&spi->word_delay, xfer); if (delay2 < 0) return delay2; -- cgit From 3e2405f01f4a1e744f2bea28aa105d7f2257c893 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:45 +0300 Subject: spi: spi-falcon: extend warning to `delay` as well The WARN_ON macro prints a warning in syslog if `delay_usecs` is non-zero. However, with the new intermediate `delay`, the warning should also be printed. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-18-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-falcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index 00f46c816a56..d3336a63f462 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -377,7 +377,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master, m->actual_length += t->len; - WARN_ON(t->delay_usecs || t->cs_change); + WARN_ON(t->delay_usecs || t->delay.value || t->cs_change); spi_flags = 0; } -- cgit From c5751ba0f71e3afe62000a9505915093efa31bd6 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:46 +0300 Subject: spi: bcm63xx: extend error condition to `delay` as well The driver errors out if `delay_usecs` is non-zero. This error condition should be extended to the new `delay` field, to account for when it will be used. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-19-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index fdd7eaa0b8ed..0f1b10a4ef0c 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -368,7 +368,7 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master, } /* CS will be deasserted directly after transfer */ - if (t->delay_usecs) { + if (t->delay_usecs || t->delay.value) { dev_err(&spi->dev, "unable to keep CS asserted after transfer\n"); status = -EINVAL; goto exit; -- cgit From acc7720de3cb9721ac07f68309dd6d7aae8e9a7a Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:47 +0300 Subject: spi: spi-axi: extend support for the `delay` field The AXI SPI engine driver uses the `delay_usecs` field from `spi_transfer` to configure delays, which the controller will execute. This change extends the logic to also include the `delay` value, in case it is used (instead if `delay_usecs`). Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-20-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-axi-spi-engine.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 74842f6019ed..eb9b78a90dcf 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -163,10 +163,21 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry, } static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry, - struct spi_engine *spi_engine, unsigned int clk_div, unsigned int delay) + struct spi_engine *spi_engine, unsigned int clk_div, + struct spi_transfer *xfer) { unsigned int spi_clk = clk_get_rate(spi_engine->ref_clk); unsigned int t; + int delay; + + if (xfer->delay_usecs) { + delay = xfer->delay_usecs; + } else { + delay = spi_delay_to_ns(&xfer->delay, xfer); + if (delay < 0) + return; + delay /= 1000; + } if (delay == 0) return; @@ -218,8 +229,7 @@ static int spi_engine_compile_message(struct spi_engine *spi_engine, spi_engine_gen_cs(p, dry, spi, true); spi_engine_gen_xfer(p, dry, xfer); - spi_engine_gen_sleep(p, dry, spi_engine, clk_div, - xfer->delay_usecs); + spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer); cs_change = xfer->cs_change; if (list_is_last(&xfer->transfer_list, &msg->transfers)) -- cgit From e74dc5c763448004ec8add422e9db53ee246acce Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 26 Sep 2019 13:51:37 +0300 Subject: spi: use new `spi_transfer_delay_exec` helper where straightforward For many places in the spi drivers, using the new `spi_transfer_delay` helper is straightforward. It's just replacing: ``` if (t->delay_usecs) udelay(t->delay_usecs); ``` with `spi_transfer_delay(t)` which handles both `delay_usecs` and the new `delay` field. This change replaces in all places (in the spi drivers) where this change is simple. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926105147.7839-10-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 3 +-- drivers/spi/spi-bcm63xx-hsspi.c | 3 +-- drivers/spi/spi-cavium.c | 3 +-- drivers/spi/spi-fsl-dspi.c | 3 +-- drivers/spi/spi-fsl-espi.c | 3 +-- drivers/spi/spi-fsl-spi.c | 3 +-- drivers/spi/spi-mpc512x-psc.c | 3 +-- drivers/spi/spi-mpc52xx-psc.c | 3 +-- drivers/spi/spi-omap-100k.c | 3 +-- drivers/spi/spi-pl022.c | 25 +++++++++++-------------- drivers/spi/spi-sc18is602.c | 3 +-- drivers/spi/spi-sh-hspi.c | 3 +-- drivers/spi/spi-topcliff-pch.c | 7 +------ drivers/spi/spi-txx9.c | 3 +-- drivers/spi/spi-xcomm.c | 3 +-- 15 files changed, 25 insertions(+), 46 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 1471b049f99a..e34ab587b980 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1366,8 +1366,7 @@ static int atmel_spi_one_transfer(struct spi_master *master, && as->use_pdc) atmel_spi_dma_unmap_xfer(master, xfer); - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); + spi_transfer_delay_exec(xfer); if (xfer->cs_change) { if (list_is_last(&xfer->transfer_list, diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index c6836a931dbf..7327309ea3d5 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -291,8 +291,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master, msg->actual_length += t->len; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); if (t->cs_change) bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); diff --git a/drivers/spi/spi-cavium.c b/drivers/spi/spi-cavium.c index 5aaf21582cb5..6854c3ce423b 100644 --- a/drivers/spi/spi-cavium.c +++ b/drivers/spi/spi-cavium.c @@ -119,8 +119,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, *rx_buf++ = (u8)v; } - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); + spi_transfer_delay_exec(xfer); return xfer->len; } diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index c0e96cc7fc51..442cff71a0d2 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -827,8 +827,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, dev_err(&dspi->pdev->dev, "Waiting for transfer to complete failed!\n"); - if (transfer->delay_usecs) - udelay(transfer->delay_usecs); + spi_transfer_delay_exec(transfer); } out: diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index f72daf66f3f3..e60581283a24 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -427,8 +427,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) ret = fsl_espi_bufs(spi, trans); - if (trans->delay_usecs) - udelay(trans->delay_usecs); + spi_transfer_delay_exec(trans); return ret; } diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 4b80ace1d137..114801a32371 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -416,8 +416,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master, } m->actual_length += t->len; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); if (cs_change) { ndelay(nsecs); diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index a337b842ae8c..ea1b07953d38 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -311,8 +311,7 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master, break; m->actual_length += t->len; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); if (cs_change) mpc512x_psc_spi_deactivate_cs(spi); diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index c7e478b9b586..17935e71b02f 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -234,8 +234,7 @@ static void mpc52xx_psc_spi_work(struct work_struct *work) break; m->actual_length += t->len; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); if (cs_change) mpc52xx_psc_spi_deactivate_cs(spi); diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 43a4785fc89b..5c704ba6d8ea 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -321,8 +321,7 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master, } } - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); /* ignore the "leave it on after last xfer" hint */ diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 7fedea67159c..3024c30e7f2e 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -485,12 +485,11 @@ static void giveback(struct pl022 *pl022) struct spi_transfer, transfer_list); /* Delay if requested before any change in chip select */ - if (last_transfer->delay_usecs) - /* - * FIXME: This runs in interrupt context. - * Is this really smart? - */ - udelay(last_transfer->delay_usecs); + /* + * FIXME: This runs in interrupt context. + * Is this really smart? + */ + spi_transfer_delay_exec(last_transfer); if (!last_transfer->cs_change) { struct spi_message *next_msg; @@ -1401,12 +1400,11 @@ static void pump_transfers(unsigned long data) previous = list_entry(transfer->transfer_list.prev, struct spi_transfer, transfer_list); - if (previous->delay_usecs) - /* - * FIXME: This runs in interrupt context. - * Is this really smart? - */ - udelay(previous->delay_usecs); + /* + * FIXME: This runs in interrupt context. + * Is this really smart? + */ + spi_transfer_delay_exec(previous); /* Reselect chip select only if cs_change was requested */ if (previous->cs_change) @@ -1520,8 +1518,7 @@ static void do_polling_transfer(struct pl022 *pl022) previous = list_entry(transfer->transfer_list.prev, struct spi_transfer, transfer_list); - if (previous->delay_usecs) - udelay(previous->delay_usecs); + spi_transfer_delay_exec(previous); if (previous->cs_change) pl022_cs_control(pl022, SSP_CHIP_SELECT); } else { diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 11acddc83304..5497eeb3bf3e 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -211,8 +211,7 @@ static int sc18is602_transfer_one(struct spi_master *master, } status = 0; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); } m->status = status; spi_finalize_current_message(master); diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 7f73f91d412a..a62034e2a7cb 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -190,8 +190,7 @@ static int hspi_transfer_one_message(struct spi_controller *ctlr, msg->actual_length += t->len; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); if (cs_change) { ndelay(nsecs); diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index f88cbb94ce12..223353fa2d8a 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1229,12 +1229,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) "%s:data->current_msg->actual_length=%d\n", __func__, data->current_msg->actual_length); - /* check for delay */ - if (data->cur_trans->delay_usecs) { - dev_dbg(&data->master->dev, "%s:delay in usec=%d\n", - __func__, data->cur_trans->delay_usecs); - udelay(data->cur_trans->delay_usecs); - } + spi_transfer_delay_exec(data->cur_trans); spin_lock(&data->lock); diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 51759d3fd45f..83daaa597acc 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -248,8 +248,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m) len -= count * wsize; } m->actual_length += t->len; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); if (!cs_change) continue; diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index a3496c46cc1b..1d9b3f03d986 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -188,8 +188,7 @@ static int spi_xcomm_transfer_one(struct spi_master *master, } status = 0; - if (t->delay_usecs) - udelay(t->delay_usecs); + spi_transfer_delay_exec(t); is_first = false; } -- cgit From 4f3d957718e7f0ac2b033dbf48c7cddecd0a8dd3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Oct 2019 13:54:25 +0300 Subject: spi: pxa2xx: No need to keep pointer to platform device There is no need to keep a pointer to the platform device. Currently there are no users of it directly, and if there will be in the future we may restore it from pointer to the struct device. Convert all users at the same time. Cc: Russell King Cc: Jaroslav Kysela Cc: Takashi Iwai Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191018105429.82782-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index bb6a14d1ab0f..59d1406a9c96 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1567,7 +1567,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->irq = platform_get_irq(pdev, 0); ssp->type = type; - ssp->pdev = pdev; + ssp->dev = &pdev->dev; ssp->port_id = pxa2xx_spi_get_port_id(adev); pdata->is_slave = of_property_read_bool(pdev->dev.of_node, "spi-slave"); -- cgit From 5ce2570513bc012020e1faaa20333a6955845f06 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Oct 2019 13:54:26 +0300 Subject: spi: pxa2xx: Sort headers Sort the headers in alphabetic order in order to ease the maintenance for this part. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191018105429.82782-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 59d1406a9c96..670734b3d56a 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -4,27 +4,27 @@ * Copyright (C) 2013, Intel Corporation */ +#include #include -#include -#include +#include +#include #include -#include -#include #include +#include +#include +#include +#include #include +#include #include +#include +#include #include #include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include "spi-pxa2xx.h" -- cgit From 365e856e18b88e360388f9de4f5da0d5b332114b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Oct 2019 13:54:27 +0300 Subject: spi: pxa2xx: Convert pxa2xx_spi_get_port_id() to take struct device This is preparatory patch before converting to use device_get_match_data() API. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191018105429.82782-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 670734b3d56a..04ca80770e35 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1476,11 +1476,13 @@ MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match); #ifdef CONFIG_ACPI -static int pxa2xx_spi_get_port_id(struct acpi_device *adev) +static int pxa2xx_spi_get_port_id(struct device *dev) { + struct acpi_device *adev; unsigned int devid; int port_id = -1; + adev = ACPI_COMPANION(dev); if (adev && adev->pnp.unique_id && !kstrtouint(adev->pnp.unique_id, 0, &devid)) port_id = devid; @@ -1489,7 +1491,7 @@ static int pxa2xx_spi_get_port_id(struct acpi_device *adev) #else /* !CONFIG_ACPI */ -static int pxa2xx_spi_get_port_id(struct acpi_device *adev) +static int pxa2xx_spi_get_port_id(struct device *dev) { return -1; } @@ -1568,7 +1570,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) ssp->irq = platform_get_irq(pdev, 0); ssp->type = type; ssp->dev = &pdev->dev; - ssp->port_id = pxa2xx_spi_get_port_id(adev); + ssp->port_id = pxa2xx_spi_get_port_id(&pdev->dev); pdata->is_slave = of_property_read_bool(pdev->dev.of_node, "spi-slave"); pdata->num_chipselect = 1; -- cgit From f2faa3ec79ac11db8c26b10f8c978d4d0f7392dd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Oct 2019 13:54:28 +0300 Subject: spi: pxa2xx: Convert to use device_get_match_data() Convert to use device_get_match_data() instead of open coded variant. While here, switch of_property_read_bool() to device_property_read_bool(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191018105429.82782-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 04ca80770e35..684a5585ac7f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1512,34 +1513,21 @@ static struct pxa2xx_spi_controller * pxa2xx_spi_init_pdata(struct platform_device *pdev) { struct pxa2xx_spi_controller *pdata; - struct acpi_device *adev; struct ssp_device *ssp; struct resource *res; - const struct acpi_device_id *adev_id = NULL; const struct pci_device_id *pcidev_id = NULL; - const struct of_device_id *of_id = NULL; enum pxa_ssp_type type; + const void *match; - adev = ACPI_COMPANION(&pdev->dev); - - if (pdev->dev.of_node) - of_id = of_match_device(pdev->dev.driver->of_match_table, - &pdev->dev); - else if (dev_is_pci(pdev->dev.parent)) + if (dev_is_pci(pdev->dev.parent)) pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, to_pci_dev(pdev->dev.parent)); - else if (adev) - adev_id = acpi_match_device(pdev->dev.driver->acpi_match_table, - &pdev->dev); - else - return NULL; - if (adev_id) - type = (enum pxa_ssp_type)adev_id->driver_data; + match = device_get_match_data(&pdev->dev); + if (match) + type = (enum pxa_ssp_type)match; else if (pcidev_id) type = (enum pxa_ssp_type)pcidev_id->driver_data; - else if (of_id) - type = (enum pxa_ssp_type)of_id->data; else return NULL; @@ -1572,7 +1560,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) ssp->dev = &pdev->dev; ssp->port_id = pxa2xx_spi_get_port_id(&pdev->dev); - pdata->is_slave = of_property_read_bool(pdev->dev.of_node, "spi-slave"); + pdata->is_slave = device_property_read_bool(&pdev->dev, "spi-slave"); pdata->num_chipselect = 1; pdata->enable_dma = true; pdata->dma_burst_size = 1; -- cgit From ae8fbf1d2403bc187a5d8fe82fbf2205d89cdb60 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Oct 2019 13:54:29 +0300 Subject: spi: pxa2xx: Replace of_device.h with mod_devicetable.h and of.h There is nothing in use from of_device.h. The definitions and macros are available thru mod_devicetable.h and of.h. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191018105429.82782-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 684a5585ac7f..443c1f4d2a9a 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include #include #include #include -- cgit From 4d8672d17450b457c0dbbcfe9868438036b4647c Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 17 Oct 2019 16:18:40 +0200 Subject: spi: atmel: Remove and fix erroneous comments Since CSAAT functionality support has been added. Some comments become wrong. Fix them to match the current driver behavior. Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191017141846.7523-2-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index e34ab587b980..7a17c3e2a8ee 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -312,11 +312,9 @@ static bool atmel_spi_is_v2(struct atmel_spi *as) * transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer * controllers have CSAAT and friends. * - * Since the CSAAT functionality is a bit weird on newer controllers as - * well, we use GPIO to control nCSx pins on all controllers, updating - * MR.PCS to avoid confusing the controller. Using GPIOs also lets us - * support active-high chipselects despite the controller's belief that - * only active-low devices/systems exists. + * Even controller newer than ar91rm9200, using GPIOs can make sens as + * it lets us support active-high chipselects despite the controller's + * belief that only active-low devices/systems exists. * * However, at91rm9200 has a second erratum whereby nCS0 doesn't work * right when driven with GPIO. ("Mode Fault does not allow more than one @@ -1193,8 +1191,6 @@ static int atmel_spi_setup(struct spi_device *spi) if (!as->use_cs_gpios) csr |= SPI_BIT(CSAAT); - /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. - */ csr |= SPI_BF(DLYBS, 0); word_delay_csr = atmel_word_delay_csr(spi, as); -- cgit From 7cbb16b2122c09f2ae393a1542fed628505b9da6 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 17 Oct 2019 16:18:41 +0200 Subject: spi: atmel: Fix CS high support Until a few years ago, this driver was only used with CS GPIO. The only exception is CS0 on AT91RM9200 which has to use internal CS. A limitation of the internal CS is that they don't support CS High. So by using the CS GPIO the CS high configuration was available except for the particular case CS0 on RM9200. When the support for the internal chip-select was added, the check of the CS high support was not updated. Due to this the driver accepts this configuration for all the SPI controller v2 (used by all SoCs excepting the AT91RM9200) whereas the hardware doesn't support it for infernal CS. This patch fixes the test to match the hardware capabilities. Fixes: 4820303480a1 ("spi: atmel: add support for the internal chip-select of the spi controller") Cc: Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191017141846.7523-3-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 7a17c3e2a8ee..6e08ae539bc0 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1176,10 +1176,8 @@ static int atmel_spi_setup(struct spi_device *spi) as = spi_master_get_devdata(spi->master); /* see notes above re chipselect */ - if (!atmel_spi_is_v2(as) - && spi->chip_select == 0 - && (spi->mode & SPI_CS_HIGH)) { - dev_dbg(&spi->dev, "setup: can't be active-high\n"); + if (!as->use_cs_gpios && (spi->mode & SPI_CS_HIGH)) { + dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n"); return -EINVAL; } -- cgit From 585d18f7ebd1dba7400dcc7189a5f7223b821374 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 17 Oct 2019 16:18:42 +0200 Subject: spi: atmel: Configure GPIO per CS instead of by controller Instead of setting up the GPIO configuration for the whole controller, do it at CS level. It will allow to mix internal CS and GPIO CS, which is not possible with the current implementation. Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191017141846.7523-4-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 6e08ae539bc0..b511df6a4846 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -275,7 +275,6 @@ struct atmel_spi { bool use_dma; bool use_pdc; - bool use_cs_gpios; bool keep_cs; bool cs_active; @@ -348,7 +347,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) } mr = spi_readl(as, MR); - if (as->use_cs_gpios) + if (asd->npcs_pin) gpiod_set_value(asd->npcs_pin, 1); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; @@ -365,7 +364,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); - if (as->use_cs_gpios && spi->chip_select != 0) + if (asd->npcs_pin && spi->chip_select != 0) gpiod_set_value(asd->npcs_pin, 1); spi_writel(as, MR, mr); } @@ -389,7 +388,7 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", mr); - if (!as->use_cs_gpios) + if (!asd->npcs_pin) spi_writel(as, CR, SPI_BIT(LASTXFER)); else if (atmel_spi_is_v2(as) || spi->chip_select != 0) gpiod_set_value(asd->npcs_pin, 0); @@ -1176,7 +1175,7 @@ static int atmel_spi_setup(struct spi_device *spi) as = spi_master_get_devdata(spi->master); /* see notes above re chipselect */ - if (!as->use_cs_gpios && (spi->mode & SPI_CS_HIGH)) { + if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH)) { dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n"); return -EINVAL; } @@ -1186,9 +1185,9 @@ static int atmel_spi_setup(struct spi_device *spi) csr |= SPI_BIT(CPOL); if (!(spi->mode & SPI_CPHA)) csr |= SPI_BIT(NCPHA); - if (!as->use_cs_gpios) - csr |= SPI_BIT(CSAAT); + if (!spi->cs_gpiod) + csr |= SPI_BIT(CSAAT); csr |= SPI_BF(DLYBS, 0); word_delay_csr = atmel_word_delay_csr(spi, as); @@ -1206,20 +1205,8 @@ static int atmel_spi_setup(struct spi_device *spi) if (!asd) return -ENOMEM; - /* - * If use_cs_gpios is true this means that we have "cs-gpios" - * defined in the device tree node so we should have - * gotten the GPIO lines from the device tree inside the - * SPI core. Warn if this is not the case but continue since - * CS GPIOs are after all optional. - */ - if (as->use_cs_gpios) { - if (!spi->cs_gpiod) { - dev_err(&spi->dev, - "host claims to use CS GPIOs but no CS found in DT by the SPI core\n"); - } + if (spi->cs_gpiod) asd->npcs_pin = spi->cs_gpiod; - } spi->controller_state = asd; } @@ -1551,13 +1538,10 @@ static int atmel_spi_probe(struct platform_device *pdev) * discovered by the SPI core when registering the SPI master * and assigned to each SPI device. */ - as->use_cs_gpios = true; if (atmel_spi_is_v2(as) && pdev->dev.of_node && - !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) { - as->use_cs_gpios = false; + !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) master->num_chipselect = 4; - } as->use_dma = false; as->use_pdc = false; -- cgit From 60086e23e64f7b3b60d957471cfd10948e25648e Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 17 Oct 2019 16:18:43 +0200 Subject: spi: atmel: Remove useless private field Since the conversion to GPIO descriptor, the GPIO used as chip select, can be directly access from the spi_device struct. So there is no need to keep the field npcs_pin. Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191017141846.7523-5-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index b511df6a4846..19600de40422 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -284,7 +284,6 @@ struct atmel_spi { /* Controller-specific per-slave state */ struct atmel_spi_device { - struct gpio_desc *npcs_pin; u32 csr; }; @@ -347,8 +346,8 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) } mr = spi_readl(as, MR); - if (asd->npcs_pin) - gpiod_set_value(asd->npcs_pin, 1); + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 1); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; @@ -364,8 +363,8 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); - if (asd->npcs_pin && spi->chip_select != 0) - gpiod_set_value(asd->npcs_pin, 1); + if (spi->cs_gpiod && spi->chip_select != 0) + gpiod_set_value(spi->cs_gpiod, 1); spi_writel(as, MR, mr); } @@ -374,7 +373,6 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) { - struct atmel_spi_device *asd = spi->controller_state; u32 mr; /* only deactivate *this* device; sometimes transfers to @@ -388,10 +386,10 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", mr); - if (!asd->npcs_pin) + if (!spi->cs_gpiod) spi_writel(as, CR, SPI_BIT(LASTXFER)); else if (atmel_spi_is_v2(as) || spi->chip_select != 0) - gpiod_set_value(asd->npcs_pin, 0); + gpiod_set_value(spi->cs_gpiod, 0); } static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock) @@ -1205,9 +1203,6 @@ static int atmel_spi_setup(struct spi_device *spi) if (!asd) return -ENOMEM; - if (spi->cs_gpiod) - asd->npcs_pin = spi->cs_gpiod; - spi->controller_state = asd; } -- cgit From 1cb84b02bf130f34ee81f99bc7dee5bca2943ed7 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 17 Oct 2019 16:18:44 +0200 Subject: spi: atmel: Remove platform data support This driver is now only used through the device tree. Simplify code by explicitly depend on device tree. Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191017141846.7523-6-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 + drivers/spi/spi-atmel.c | 16 ++-------------- 2 files changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6f7fdcbb9151..6c0c1f55bd71 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -80,6 +80,7 @@ config SPI_ARMADA_3700 config SPI_ATMEL tristate "Atmel SPI Controller" depends on ARCH_AT91 || COMPILE_TEST + depends on OF help This selects a driver for the Atmel SPI Controller, present on many AT91 ARM chips. diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 19600de40422..1ff5b20eabf7 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1500,7 +1500,7 @@ static int atmel_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); master->dev.of_node = pdev->dev.of_node; master->bus_num = pdev->id; - master->num_chipselect = master->dev.of_node ? 0 : 4; + master->num_chipselect = 4; master->setup = atmel_spi_setup; master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX); master->transfer_one_message = atmel_spi_transfer_one_message; @@ -1528,16 +1528,6 @@ static int atmel_spi_probe(struct platform_device *pdev) atmel_get_caps(as); - /* - * If there are chip selects in the device tree, those will be - * discovered by the SPI core when registering the SPI master - * and assigned to each SPI device. - */ - if (atmel_spi_is_v2(as) && - pdev->dev.of_node && - !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) - master->num_chipselect = 4; - as->use_dma = false; as->use_pdc = false; if (as->caps.has_dma_support) { @@ -1745,20 +1735,18 @@ static const struct dev_pm_ops atmel_spi_pm_ops = { #define ATMEL_SPI_PM_OPS NULL #endif -#if defined(CONFIG_OF) static const struct of_device_id atmel_spi_dt_ids[] = { { .compatible = "atmel,at91rm9200-spi" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids); -#endif static struct platform_driver atmel_spi_driver = { .driver = { .name = "atmel_spi", .pm = ATMEL_SPI_PM_OPS, - .of_match_table = of_match_ptr(atmel_spi_dt_ids), + .of_match_table = atmel_spi_dt_ids, }, .probe = atmel_spi_probe, .remove = atmel_spi_remove, -- cgit From 57e3137710443a3227a54c425b9c606425678c8f Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 17 Oct 2019 16:18:45 +0200 Subject: spi: atmel: Improve and fix GPIO CS usage In the previous implementation of this driver, the index of the GPIO used as CS was linked to the offset of the CS register used to configure the transfer. With this new implementation the first CS register not used by internal CS is associated to all the GPIO CS. It allows to not be anymore limited to have only 4 CS managed, now it is possible to have in the same time until 3 internal CS and no more limit for the CS GPIO. Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191017141846.7523-7-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 74 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 8 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 1ff5b20eabf7..ac5e2ddf9e1b 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -280,6 +280,8 @@ struct atmel_spi { bool cs_active; u32 fifo_size; + u8 native_cs_free; + u8 native_cs_for_gpio; }; /* Controller-specific per-slave state */ @@ -324,23 +326,29 @@ static bool atmel_spi_is_v2(struct atmel_spi *as) static void cs_activate(struct atmel_spi *as, struct spi_device *spi) { struct atmel_spi_device *asd = spi->controller_state; + int chip_select; u32 mr; + if (spi->cs_gpiod) + chip_select = as->native_cs_for_gpio; + else + chip_select = spi->chip_select; + if (atmel_spi_is_v2(as)) { - spi_writel(as, CSR0 + 4 * spi->chip_select, asd->csr); + spi_writel(as, CSR0 + 4 * chip_select, asd->csr); /* For the low SPI version, there is a issue that PDC transfer * on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS */ spi_writel(as, CSR0, asd->csr); if (as->caps.has_wdrbt) { spi_writel(as, MR, - SPI_BF(PCS, ~(0x01 << spi->chip_select)) + SPI_BF(PCS, ~(0x01 << chip_select)) | SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); } else { spi_writel(as, MR, - SPI_BF(PCS, ~(0x01 << spi->chip_select)) + SPI_BF(PCS, ~(0x01 << chip_select)) | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); } @@ -362,7 +370,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) } mr = spi_readl(as, MR); - mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); + mr = SPI_BFINS(PCS, ~(1 << chip_select), mr); if (spi->cs_gpiod && spi->chip_select != 0) gpiod_set_value(spi->cs_gpiod, 1); spi_writel(as, MR, mr); @@ -373,13 +381,19 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) { + int chip_select; u32 mr; + if (spi->cs_gpiod) + chip_select = as->native_cs_for_gpio; + else + chip_select = spi->chip_select; + /* only deactivate *this* device; sometimes transfers to * another device may be active when this routine is called. */ mr = spi_readl(as, MR); - if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) { + if (~SPI_BFEXT(PCS, mr) & (1 << chip_select)) { mr = SPI_BFINS(PCS, 0xf, mr); spi_writel(as, MR, mr); } @@ -815,6 +829,12 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as, { u32 scbr, csr; unsigned long bus_hz; + int chip_select; + + if (spi->cs_gpiod) + chip_select = as->native_cs_for_gpio; + else + chip_select = spi->chip_select; /* v1 chips start out at half the peripheral bus speed. */ bus_hz = as->spi_clk; @@ -843,9 +863,9 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as, xfer->speed_hz, scbr, bus_hz); return -EINVAL; } - csr = spi_readl(as, CSR0 + 4 * spi->chip_select); + csr = spi_readl(as, CSR0 + 4 * chip_select); csr = SPI_BFINS(SCBR, scbr, csr); - spi_writel(as, CSR0 + 4 * spi->chip_select, csr); + spi_writel(as, CSR0 + 4 * chip_select, csr); return 0; } @@ -1162,12 +1182,32 @@ static int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as) return (as->spi_clk / 1000000 * value) >> 5; } +static void initialize_native_cs_for_gpio(struct atmel_spi *as) +{ + int i; + struct spi_master *master = platform_get_drvdata(as->pdev); + + if (!as->native_cs_free) + return; /* already initialized */ + + if (!master->cs_gpiods) + return; /* No CS GPIO */ + + for (i = 0; i < 4; i++) + if (master->cs_gpiods[i]) + as->native_cs_free |= BIT(i); + + if (as->native_cs_free) + as->native_cs_for_gpio = ffs(as->native_cs_free); +} + static int atmel_spi_setup(struct spi_device *spi) { struct atmel_spi *as; struct atmel_spi_device *asd; u32 csr; unsigned int bits = spi->bits_per_word; + int chip_select; int word_delay_csr; as = spi_master_get_devdata(spi->master); @@ -1178,6 +1218,24 @@ static int atmel_spi_setup(struct spi_device *spi) return -EINVAL; } + /* Setup() is called during spi_register_controller(aka + * spi_register_master) but after all membmers of the cs_gpiod + * array have been filled, so we can looked for which native + * CS will be free for using with GPIO + */ + initialize_native_cs_for_gpio(as); + + if (spi->cs_gpiod && as->native_cs_free) { + dev_err(&spi->dev, + "No native CS available to support this GPIO CS\n"); + return -EBUSY; + } + + if (spi->cs_gpiod) + chip_select = as->native_cs_for_gpio; + else + chip_select = spi->chip_select; + csr = SPI_BF(BITS, bits - 8); if (spi->mode & SPI_CPOL) csr |= SPI_BIT(CPOL); @@ -1213,7 +1271,7 @@ static int atmel_spi_setup(struct spi_device *spi) bits, spi->mode, spi->chip_select, csr); if (!atmel_spi_is_v2(as)) - spi_writel(as, CSR0 + 4 * spi->chip_select, csr); + spi_writel(as, CSR0 + 4 * chip_select, csr); return 0; } -- cgit From 9c86f12a36479dec06df3e4a4f31cecf8eba0222 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 17 Oct 2019 16:18:46 +0200 Subject: spi: atmel: Improve CS0 case support on AT91RM9200 Thanks to the recent change in this driver, it is now possible to prevent using the CS0 with GPIO during setup. It then allows to remove the special handling of this case in the cs_activate() and cs_deactivate() functions. Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191017141846.7523-8-gregory.clement@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index ac5e2ddf9e1b..d88e2aa64839 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -371,7 +371,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << chip_select), mr); - if (spi->cs_gpiod && spi->chip_select != 0) + if (spi->cs_gpiod) gpiod_set_value(spi->cs_gpiod, 1); spi_writel(as, MR, mr); } @@ -402,7 +402,7 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) if (!spi->cs_gpiod) spi_writel(as, CR, SPI_BIT(LASTXFER)); - else if (atmel_spi_is_v2(as) || spi->chip_select != 0) + else gpiod_set_value(spi->cs_gpiod, 0); } @@ -1193,7 +1193,16 @@ static void initialize_native_cs_for_gpio(struct atmel_spi *as) if (!master->cs_gpiods) return; /* No CS GPIO */ - for (i = 0; i < 4; i++) + /* + * On the first version of the controller (AT91RM9200), CS0 + * can't be used associated with GPIO + */ + if (atmel_spi_is_v2(as)) + i = 0; + else + i = 1; + + for (; i < 4; i++) if (master->cs_gpiods[i]) as->native_cs_free |= BIT(i); -- cgit From c8169580e924a1d2821e0a2e228c674e0eaa091f Mon Sep 17 00:00:00 2001 From: Raymond Tan Date: Fri, 18 Oct 2019 16:21:30 +0300 Subject: spi: dw-pci: Add runtime power management support Implement pm_runtime hooks at pci driver. Signed-off-by: Raymond Tan [jarkko.nikula@linux.intel.com: Forward ported on top of commit 1e6959832510 ("spi: dw: Add basic runtime PM support")] Signed-off-by: Jarkko Nikula Link: https://lore.kernel.org/r/20191018132131.31608-2-jarkko.nikula@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 7ab53f4d04b9..1cddecea2715 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,11 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", pdev->vendor, pdev->device); + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + pm_runtime_allow(&pdev->dev); + return 0; } @@ -108,6 +114,9 @@ static void spi_pci_remove(struct pci_dev *pdev) { struct dw_spi *dws = pci_get_drvdata(pdev); + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + dw_spi_remove_host(dws); pci_free_irq_vectors(pdev); } -- cgit From c97905cae914ad955b79212a454016a68c7a1a21 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 18 Oct 2019 16:21:31 +0300 Subject: spi: dw-pci: Fix Chip Select amount on Intel Elkhart Lake PSE SPI Intel(R) Programmable Services Engine (Intel(R) PSE) SPI controllers in Intel Elkhart Lake have two Chip Select signals instead of one. Reported-by: Raymond Tan Signed-off-by: Jarkko Nikula Link: https://lore.kernel.org/r/20191018132131.31608-3-jarkko.nikula@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 1cddecea2715..12c131b5fb4e 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -36,7 +36,7 @@ static struct spi_pci_desc spi_pci_mid_desc_2 = { }; static struct spi_pci_desc spi_pci_ehl_desc = { - .num_cs = 1, + .num_cs = 2, .bus_num = -1, .max_freq = 100000000, }; -- cgit From be73e323aee4e10eccef2b0f862c0196f392f012 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 23 Oct 2019 15:16:43 +0300 Subject: spi: Fix spelling in the comments Two spelling mistakes are being fixed. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191023121643.25237-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5414a10afd65..5ba19ef809c2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -92,7 +92,7 @@ static ssize_t driver_override_store(struct device *dev, if (len) { spi->driver_override = driver_override; } else { - /* Emptry string, disable driver override */ + /* Empty string, disable driver override */ spi->driver_override = NULL; kfree(driver_override); } @@ -469,7 +469,7 @@ static LIST_HEAD(board_list); static LIST_HEAD(spi_controller_list); /* - * Used to protect add/del opertion for board_info list and + * Used to protect add/del operation for board_info list and * spi_controller list, and their matching process * also used to protect object of type struct idr */ -- cgit From e58f7d15e6beb255b3907054a0536db77c979a31 Mon Sep 17 00:00:00 2001 From: Alvaro Gamez Machado Date: Thu, 24 Oct 2019 13:07:56 +0200 Subject: spi: xilinx: Add DT support for selecting transfer word width This core supports either 8, 16 or 32 bits as word width. This value is only settable on instantiation, and thus we need to support any of them by means of the device tree. Signed-off-by: Alvaro Gamez Machado Link: https://lore.kernel.org/r/20191024110757.25820-3-alvaro.gamez@hazent.com Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index d5f9d5fbb3e8..8dd2bb99cb4d 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -391,7 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) struct xilinx_spi *xspi; struct xspi_platform_data *pdata; struct resource *res; - int ret, num_cs = 0, bits_per_word = 8; + int ret, num_cs = 0, bits_per_word; struct spi_master *master; u32 tmp; u8 i; @@ -403,6 +403,11 @@ static int xilinx_spi_probe(struct platform_device *pdev) } else { of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits", &num_cs); + ret = of_property_read_u32(pdev->dev.of_node, + "xlnx,num-transfer-bits", + &bits_per_word); + if (ret) + bits_per_word = 8; } if (!num_cs) { -- cgit From 6fb7427d84f6ed064776434436485cfb0f6711e9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Oct 2019 13:36:24 +0300 Subject: spi: pxa2xx: Introduce temporary variables to increase readability The current conditional for PCI ID matching is hard to read. Introduce couple of temporary variables to increase readability of the code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191021103625.4250-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 443c1f4d2a9a..6eb6805ee51d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1516,13 +1516,14 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) struct pxa2xx_spi_controller *pdata; struct ssp_device *ssp; struct resource *res; + struct device *parent = pdev->dev.parent; + struct pci_dev *pcidev = dev_is_pci(parent) ? to_pci_dev(parent) : NULL; const struct pci_device_id *pcidev_id = NULL; enum pxa_ssp_type type; const void *match; - if (dev_is_pci(pdev->dev.parent)) - pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, - to_pci_dev(pdev->dev.parent)); + if (pcidev) + pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, pcidev); match = device_get_match_data(&pdev->dev); if (match) @@ -1549,8 +1550,8 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) #ifdef CONFIG_PCI if (pcidev_id) { - pdata->tx_param = pdev->dev.parent; - pdata->rx_param = pdev->dev.parent; + pdata->tx_param = parent; + pdata->rx_param = parent; pdata->dma_filter = pxa2xx_spi_idma_filter; } #endif -- cgit From 91ea1d70607e374b014b4b9bea771ce661f9f64b Mon Sep 17 00:00:00 2001 From: Lingling Xu Date: Mon, 28 Oct 2019 18:10:30 +0800 Subject: spi: sprd: adi: Add missing lock protection when rebooting When rebooting the system, we should lock the watchdog after configuration to make sure the watchdog can reboot the system successfully. Signed-off-by: Lingling Xu Signed-off-by: Baolin Wang Link: https://lore.kernel.org/r/7b04711127434555e3a1a86bc6be99860cd86668.1572257085.git.baolin.wang@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-sprd-adi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c index 9a051286f120..9613cfe3c0a2 100644 --- a/drivers/spi/spi-sprd-adi.c +++ b/drivers/spi/spi-sprd-adi.c @@ -393,6 +393,9 @@ static int sprd_adi_restart_handler(struct notifier_block *this, val |= BIT_WDG_RUN | BIT_WDG_RST; sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val); + /* Lock the watchdog */ + sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, ~WDG_UNLOCK_KEY); + mdelay(1000); dev_emerg(sadi->dev, "Unable to restart system\n"); -- cgit From 1d00a67c2da2d8d82e6dcc5b398d9f6db656d9be Mon Sep 17 00:00:00 2001 From: Lingling Xu Date: Mon, 28 Oct 2019 18:10:31 +0800 Subject: spi: sprd: adi: Set BIT_WDG_NEW bit when rebooting When rebooting system, the PMIC watchdog time loading may not be loaded correctly when another system is feeding the PMIC watchdog, since we did not check the watchdog busy status before loading time values. Thus we should set the BIT_WDG_NEW bit before loading time values, that can support multiple loads without checking busy status to make sure the time values can be loaded successfully to avoid this potential issue. Signed-off-by: Lingling Xu Signed-off-by: Baolin Wang Link: https://lore.kernel.org/r/5655318a7252c9ea518c2f7950a61228ab8f42bf.1572257085.git.baolin.wang@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-sprd-adi.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c index 9613cfe3c0a2..87dadb6b8ebf 100644 --- a/drivers/spi/spi-sprd-adi.c +++ b/drivers/spi/spi-sprd-adi.c @@ -77,6 +77,7 @@ /* Bits definitions for register REG_WDG_CTRL */ #define BIT_WDG_RUN BIT(1) +#define BIT_WDG_NEW BIT(2) #define BIT_WDG_RST BIT(3) /* Registers definitions for PMIC */ @@ -383,6 +384,10 @@ static int sprd_adi_restart_handler(struct notifier_block *this, /* Unlock the watchdog */ sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY); + sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val); + val |= BIT_WDG_NEW; + sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val); + /* Load the watchdog timeout value, 50ms is always enough. */ sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW, WDG_LOAD_VAL & WDG_LOAD_MASK); -- cgit From 76f0030f367c61d4d1f4b1393ff3d9dc43d20c6a Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 30 Oct 2019 13:31:37 +0200 Subject: spi: dw: Remove runtime PM enable/disable from common part of the driver Committed version of the commit b9fc2d207e54 ("spi: dw: Move runtime PM enable/disable from common to platform driver part") does not include by some reason changes to drivers/spi/spi-dw.c that were part of the original patch sent to the mailing list. Complete the code move by doing those changes now. Fixes: b9fc2d207e54 ("spi: dw: Move runtime PM enable/disable from common to platform driver part") Cc: Phil Edworthy Signed-off-by: Jarkko Nikula Link: https://lore.kernel.org/r/20191030113137.15459-1-jarkko.nikula@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 54ed6eb3e252..466f5c67843b 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -499,8 +498,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) if (dws->set_cs) master->set_cs = dws->set_cs; - pm_runtime_enable(dev); - /* Basic HW init */ spi_hw_init(dev, dws); @@ -529,7 +526,6 @@ err_dma_exit: spi_enable_chip(dws, 0); free_irq(dws->irq, master); err_free_master: - pm_runtime_disable(dev); spi_controller_put(master); return ret; } @@ -544,9 +540,6 @@ void dw_spi_remove_host(struct dw_spi *dws) spi_shutdown_chip(dws); - if (dws->master) - pm_runtime_disable(&dws->master->dev); - free_irq(dws->irq, dws->master); } EXPORT_SYMBOL_GPL(dw_spi_remove_host); -- cgit From c8b348dd86091daa3496a6dc8c0777b78c9683a6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Oct 2019 08:38:32 +0100 Subject: spi: txx9: Convert to use GPIO descriptors This converts the TXX9 SPI driver to use GPIO descriptors to control the GPIO chip selects. As the driver was clearly (ab)using the device tree "reg" property to offset into the global GPIO chip we have to add a hack to counter the hack: add a 1-to-1 chip select to GPIO offset mapping for all 16 lines on the TXX9 GPIO chip. The details are described in a largeish comment in the patch. We do not need to set up the GPIO as output any more since the core will take care of this, as well as it will handle the polarity inversion semantics. Cc: Atsushi Nemoto Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20191030073832.24038-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-txx9.c | 75 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 17 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 83daaa597acc..3606232f190f 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -26,7 +26,8 @@ #include #include #include -#include +#include +#include #define SPI_FIFO_SIZE 4 @@ -79,7 +80,7 @@ struct txx9spi { void __iomem *membase; int baseclk; struct clk *clk; - int last_chipselect; + struct gpio_desc *last_chipselect; int last_chipselect_val; }; @@ -95,20 +96,22 @@ static void txx9spi_wr(struct txx9spi *c, u32 val, int reg) static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c, int on, unsigned int cs_delay) { - int val = (spi->mode & SPI_CS_HIGH) ? on : !on; - + /* + * The GPIO descriptor will track polarity inversion inside + * gpiolib. + */ if (on) { /* deselect the chip with cs_change hint in last transfer */ - if (c->last_chipselect >= 0) - gpio_set_value(c->last_chipselect, + if (c->last_chipselect) + gpiod_set_value(c->last_chipselect, !c->last_chipselect_val); - c->last_chipselect = spi->chip_select; - c->last_chipselect_val = val; + c->last_chipselect = spi->cs_gpiod; + c->last_chipselect_val = on; } else { - c->last_chipselect = -1; + c->last_chipselect = NULL; ndelay(cs_delay); /* CS Hold Time */ } - gpio_set_value(spi->chip_select, val); + gpiod_set_value(spi->cs_gpiod, on); ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */ } @@ -119,12 +122,6 @@ static int txx9spi_setup(struct spi_device *spi) if (!spi->max_speed_hz) return -EINVAL; - if (gpio_direction_output(spi->chip_select, - !(spi->mode & SPI_CS_HIGH))) { - dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n"); - return -EINVAL; - } - /* deselect chip */ spin_lock(&c->lock); txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz); @@ -319,6 +316,47 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) return 0; } +/* + * Chip select uses GPIO only, further the driver is using the chip select + * numer (from the device tree "reg" property, and this can only come from + * device tree since this i MIPS and there is no way to pass platform data) as + * the GPIO number. As the platform has only one GPIO controller (the txx9 GPIO + * chip) it is thus using the chip select number as an offset into that chip. + * This chip has a maximum of 16 GPIOs 0..15 and this is what all platforms + * register. + * + * We modernized this behaviour by explicitly converting that offset to an + * offset on the GPIO chip using a GPIO descriptor machine table of the same + * size as the txx9 GPIO chip with a 1-to-1 mapping of chip select to GPIO + * offset. + * + * This is admittedly a hack, but it is countering the hack of using "reg" to + * contain a GPIO offset when it should be using "cs-gpios" as the SPI bindings + * state. + */ +static struct gpiod_lookup_table txx9spi_cs_gpio_table = { + .dev_id = "spi0", + .table = { + GPIO_LOOKUP_IDX("TXx9", 0, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 1, "cs", 1, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 2, "cs", 2, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 3, "cs", 3, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 4, "cs", 4, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 5, "cs", 5, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 6, "cs", 6, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 7, "cs", 7, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 8, "cs", 8, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 9, "cs", 9, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 10, "cs", 10, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 11, "cs", 11, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 12, "cs", 12, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 13, "cs", 13, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 14, "cs", 14, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("TXx9", 15, "cs", 15, GPIO_ACTIVE_LOW), + { }, + }, +}; + static int txx9spi_probe(struct platform_device *dev) { struct spi_master *master; @@ -372,12 +410,14 @@ static int txx9spi_probe(struct platform_device *dev) if (ret) goto exit; - c->last_chipselect = -1; + c->last_chipselect = NULL; dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n", (unsigned long long)res->start, irq, (c->baseclk + 500000) / 1000000); + gpiod_add_lookup_table(&txx9spi_cs_gpio_table); + /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; @@ -386,6 +426,7 @@ static int txx9spi_probe(struct platform_device *dev) master->transfer = txx9spi_transfer; master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */ master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + master->use_gpio_descriptors = true; ret = devm_spi_register_master(&dev->dev, master); if (ret) -- cgit From 26fa680ba9a13d6b05df201b3dfd946a7d915644 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Oct 2019 08:34:18 +0100 Subject: spi: dw: Drop GPIO header The DW driver does not use the legacy GPIO header so drop it from the spi-dw.h include. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20191030073418.23717-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-dw.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index c9c15881e982..38c7de1f0aa9 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -4,7 +4,6 @@ #include #include -#include /* Register offsets */ #define DW_SPI_CTRL0 0x00 -- cgit From c618a90dcaf3ffd37ec3b16451297e90a1a8395c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Oct 2019 08:36:24 +0100 Subject: spi: zynq-qspi: Drop GPIO header This driver does not use any symbols from the legacy GPIO header so drop the include. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20191030073624.23974-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 5cf6993ddce5..8786054f4869 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include -- cgit From d948e6ca189985495a21cd622c31e30e72b6b688 Mon Sep 17 00:00:00 2001 From: Luhua Xu Date: Wed, 30 Oct 2019 17:03:54 +0800 Subject: spi: add power control when set_cs As to set_cs takes effect immediately, power spi is needed when setup spi. Cc: Mark Brown Signed-off-by: Luhua Xu Link: https://lore.kernel.org/r/1572426234-30019-1-git-send-email-luhua.xu@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5ba19ef809c2..294d0038eea6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3261,7 +3261,20 @@ int spi_setup(struct spi_device *spi) if (spi->controller->setup) status = spi->controller->setup(spi); - spi_set_cs(spi, false); + if (spi->controller->auto_runtime_pm && spi->controller->set_cs) { + status = pm_runtime_get_sync(spi->controller->dev.parent); + if (status < 0) { + pm_runtime_put_noidle(spi->controller->dev.parent); + dev_err(&spi->controller->dev, "Failed to power device: %d\n", + status); + return status; + } + spi_set_cs(spi, false); + pm_runtime_mark_last_busy(spi->controller->dev.parent); + pm_runtime_put_autosuspend(spi->controller->dev.parent); + } else { + spi_set_cs(spi, false); + } if (spi->rt && !spi->controller->rt) { spi->controller->rt = true; -- cgit From e9a8ba9769a0e354341bc6cc01b98aadcea1dfe9 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Wed, 6 Nov 2019 10:36:09 +0800 Subject: spi: img-spfi: fix potential double release The channels spfi->tx_ch and spfi->rx_ch are not set to NULL after they are released. As a result, they will be released again, either on the error handling branch in the same function or in the corresponding remove function, i.e. img_spfi_remove(). This patch fixes the bug by setting the two members to NULL. Signed-off-by: Pan Bian Link: https://lore.kernel.org/r/1573007769-20131-1-git-send-email-bianpan2016@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-img-spfi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 439b01e4a2c8..f4a8f470aecc 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -673,6 +673,8 @@ static int img_spfi_probe(struct platform_device *pdev) dma_release_channel(spfi->tx_ch); if (spfi->rx_ch) dma_release_channel(spfi->rx_ch); + spfi->tx_ch = NULL; + spfi->rx_ch = NULL; dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n"); } else { master->dma_tx = spfi->tx_ch; -- cgit From 27fb2313f28d8c82adace68bf49f12fe810ba58c Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 7 Nov 2019 17:42:34 +1300 Subject: spi: bcm-qspi: Convert to use CS GPIO descriptors Set use_gpio_descriptors to true and avoid asserting the native chip select if the spi core has done it for us. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20191107044235.4864-2-chris.packham@alliedtelesis.co.nz Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 7a3531856491..85bad70f59e3 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -803,7 +803,8 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi, return -EIO; from = op->addr.val; - bcm_qspi_chip_select(qspi, spi->chip_select); + if (!spi->cs_gpiod) + bcm_qspi_chip_select(qspi, spi->chip_select); bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0); /* @@ -882,7 +883,8 @@ static int bcm_qspi_transfer_one(struct spi_master *master, int slots; unsigned long timeo = msecs_to_jiffies(100); - bcm_qspi_chip_select(qspi, spi->chip_select); + if (!spi->cs_gpiod) + bcm_qspi_chip_select(qspi, spi->chip_select); qspi->trans_pos.trans = trans; qspi->trans_pos.byte = 0; @@ -1234,6 +1236,7 @@ int bcm_qspi_probe(struct platform_device *pdev, master->cleanup = bcm_qspi_cleanup; master->dev.of_node = dev->of_node; master->num_chipselect = NUM_CHIPSELECT; + master->use_gpio_descriptors = true; qspi->big_endian = of_device_is_big_endian(dev->of_node); -- cgit From 05766050d5bd9af24dcaec6b29255a6f2b324543 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 7 Nov 2019 17:42:35 +1300 Subject: spi: spi-mem: fallback to using transfers when CS gpios are used Devices with chip selects driven via GPIO are not compatible with the spi-mem operations. Fallback to using standard spi transfers when the device is connected with a gpio CS. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20191107044235.4864-3-chris.packham@alliedtelesis.co.nz Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 9f0fa9f3116d..e5a46f0eb93b 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -286,7 +286,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) if (!spi_mem_internal_supports_op(mem, op)) return -ENOTSUPP; - if (ctlr->mem_ops) { + if (ctlr->mem_ops && !mem->spi->cs_gpiod) { ret = spi_mem_access_start(mem); if (ret) return ret; -- cgit From 9b10fa363baf3a506b089f3df3a5afd5e2f244db Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Nov 2019 11:59:15 +0100 Subject: spi: zynq-qspi: Keep the naming consistent across the driver In this driver (and also in a lot of other drivers in drivers/spi/), the spi_controller structure is sometimes referred as 'ctlr' and sometimes as 'ctrl'. Grepping there shows that 'ctlr' seems to be more common so keep the naming consistent in this driver and s/ctrl/ctlr/. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20191108105920.19014-3-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 8786054f4869..b1c56e9d7c94 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -283,8 +283,8 @@ static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size) */ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert) { - struct spi_controller *ctrl = spi->master; - struct zynq_qspi *xqspi = spi_controller_get_devdata(ctrl); + struct spi_controller *ctlr = spi->master; + struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); u32 config_reg; config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET); @@ -364,10 +364,10 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi) */ static int zynq_qspi_setup_op(struct spi_device *spi) { - struct spi_controller *ctrl = spi->master; - struct zynq_qspi *qspi = spi_controller_get_devdata(ctrl); + struct spi_controller *ctlr = spi->master; + struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr); - if (ctrl->busy) + if (ctlr->busy) return -EBUSY; clk_enable(qspi->refclk); -- cgit From 087622d09472f96f1f5d6ced36ca75c92e86af21 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Nov 2019 15:07:38 +0100 Subject: spi: zynq-qspi: Anything else than CS0 is not supported yet Unlike what the driver is currently advertizing, CS0 only can be used, CS1 is not supported at all. Prevent people to use CS1. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20191108140744.1734-2-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index b1c56e9d7c94..9f53ea08adf7 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -680,10 +680,14 @@ static int zynq_qspi_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "num-cs", &num_cs); - if (ret < 0) + if (ret < 0) { ctlr->num_chipselect = ZYNQ_QSPI_DEFAULT_NUM_CS; - else + } else if (num_cs > ZYNQ_QSPI_DEFAULT_NUM_CS) { + dev_err(&pdev->dev, "anything but CS0 is not yet supported\n"); + goto remove_master; + } else { ctlr->num_chipselect = num_cs; + } ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; -- cgit From 941be723735113028361c4664cd10134d3d27006 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Nov 2019 15:07:40 +0100 Subject: spi: zynq-qspi: Keep the bitfields naming consistent Most of the bits/bitfields #define'd in this driver are composed with: 1/ the driver prefix 2/ the name of the register they apply to Keep the naming consistent by applying this rule to the CONFIG register internals. These definitions will be used in a following change set. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20191108140744.1734-4-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 9f53ea08adf7..530533b6c974 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -60,9 +60,9 @@ * These are the values used in the calculation of baud rate divisor and * setting the slave select. */ -#define ZYNQ_QSPI_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */ -#define ZYNQ_QSPI_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift in CR */ -#define ZYNQ_QSPI_SS_SHIFT 10 /* Slave Select field shift in CR */ +#define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */ +#define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */ +#define ZYNQ_QSPI_CONFIG_PCS 10 /* Peripheral Chip Select */ /* * QSPI Interrupt Registers bit Masks @@ -292,7 +292,7 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert) /* Select the slave */ config_reg &= ~ZYNQ_QSPI_CONFIG_SSCTRL_MASK; config_reg |= (((~(BIT(spi->chip_select))) << - ZYNQ_QSPI_SS_SHIFT) & + ZYNQ_QSPI_CONFIG_PCS) & ZYNQ_QSPI_CONFIG_SSCTRL_MASK); } else { config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK; @@ -331,7 +331,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi) * ---------------- * 111 - divide by 256 */ - while ((baud_rate_val < ZYNQ_QSPI_BAUD_DIV_MAX) && + while ((baud_rate_val < ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX) && (clk_get_rate(xqspi->refclk) / (2 << baud_rate_val)) > spi->max_speed_hz) baud_rate_val++; @@ -347,7 +347,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi) config_reg |= ZYNQ_QSPI_CONFIG_CPOL_MASK; config_reg &= ~ZYNQ_QSPI_CONFIG_BDRATE_MASK; - config_reg |= (baud_rate_val << ZYNQ_QSPI_BAUD_DIV_SHIFT); + config_reg |= (baud_rate_val << ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT); zynq_qspi_write(xqspi, ZYNQ_QSPI_CONFIG_OFFSET, config_reg); return 0; -- cgit From 044ac826200f08adebe3207a618d829279e9f3b1 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Nov 2019 15:07:41 +0100 Subject: spi: zynq-qspi: Enhance the Linear CFG bit definitions Using masks makes sense when manipulating fields of several bits. When only one bit is involved, it is usual to just use the BIT() macro but in this case using the term mask is abusive. Fix the #define macros and their comments. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20191108140744.1734-5-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 530533b6c974..70ecefd817f7 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -98,9 +98,9 @@ * It is named Linear Configuration but it controls other modes when not in * linear mode also. */ -#define ZYNQ_QSPI_LCFG_TWO_MEM_MASK BIT(30) /* LQSPI Two memories Mask */ -#define ZYNQ_QSPI_LCFG_SEP_BUS_MASK BIT(29) /* LQSPI Separate bus Mask */ -#define ZYNQ_QSPI_LCFG_U_PAGE_MASK BIT(28) /* LQSPI Upper Page Mask */ +#define ZYNQ_QSPI_LCFG_TWO_MEM BIT(30) /* LQSPI Two memories */ +#define ZYNQ_QSPI_LCFG_SEP_BUS BIT(29) /* LQSPI Separate bus */ +#define ZYNQ_QSPI_LCFG_U_PAGE BIT(28) /* LQSPI Upper Page */ #define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8 -- cgit From dffaf7439979e6dbb820633bb4f44dcadcac847e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Nov 2019 15:07:42 +0100 Subject: spi: zynq-qspi: Clarify the select chip function The code used to assert and de-assert a chip select line is very complicated for no reason. Simplify the logic by either setting or resetting the concerned bit, which actually only changes an electrical state. Update the comment to reflect that there is no possibility to actually choose a CS as the default (CS0) will be driven in any case. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20191108140744.1734-6-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 70ecefd817f7..80e51c894eaa 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -50,7 +50,6 @@ #define ZYNQ_QSPI_CONFIG_BDRATE_MASK GENMASK(5, 3) /* Baud Rate Mask */ #define ZYNQ_QSPI_CONFIG_CPHA_MASK BIT(2) /* Clock Phase Control */ #define ZYNQ_QSPI_CONFIG_CPOL_MASK BIT(1) /* Clock Polarity Control */ -#define ZYNQ_QSPI_CONFIG_SSCTRL_MASK BIT(10) /* Slave Select Mask */ #define ZYNQ_QSPI_CONFIG_FWIDTH_MASK GENMASK(7, 6) /* FIFO width */ #define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */ @@ -62,7 +61,7 @@ */ #define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */ #define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */ -#define ZYNQ_QSPI_CONFIG_PCS 10 /* Peripheral Chip Select */ +#define ZYNQ_QSPI_CONFIG_PCS BIT(10) /* Peripheral Chip Select */ /* * QSPI Interrupt Registers bit Masks @@ -287,16 +286,12 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert) struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); u32 config_reg; + /* Ground the line to assert the CS */ config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET); - if (assert) { - /* Select the slave */ - config_reg &= ~ZYNQ_QSPI_CONFIG_SSCTRL_MASK; - config_reg |= (((~(BIT(spi->chip_select))) << - ZYNQ_QSPI_CONFIG_PCS) & - ZYNQ_QSPI_CONFIG_SSCTRL_MASK); - } else { - config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK; - } + if (assert) + config_reg &= ~ZYNQ_QSPI_CONFIG_PCS; + else + config_reg |= ZYNQ_QSPI_CONFIG_PCS; zynq_qspi_write(xqspi, ZYNQ_QSPI_CONFIG_OFFSET, config_reg); } -- cgit From 8f16292d8b492ca6b0d58ac0769de1c1a7bbb544 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Nov 2019 15:07:43 +0100 Subject: spi: zynq-qspi: Do the actual hardware initialization later in the probe Supporting more than one CS will need some tweaking of the linear configuration register which is (rightfully) initialized in the hardware initialization helper. The extra initialization needs the knowledge of the actual number of CS, which is retrieved by reading the value of the num-cs DT property. As the initialization helper is called pretty early and might be called much later in the probe without side effect, let's delay it a bit so that the number of CS will be available when running this helper. This way, adding support for multiple CS lines in a next patch will be eased. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20191108140744.1734-7-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 80e51c894eaa..e76f9c9738f0 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -657,9 +657,6 @@ static int zynq_qspi_probe(struct platform_device *pdev) goto clk_dis_pclk; } - /* QSPI controller initializations */ - zynq_qspi_init_hw(xqspi); - xqspi->irq = platform_get_irq(pdev, 0); if (xqspi->irq <= 0) { ret = -ENXIO; @@ -690,6 +687,10 @@ static int zynq_qspi_probe(struct platform_device *pdev) ctlr->setup = zynq_qspi_setup_op; ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2; ctlr->dev.of_node = np; + + /* QSPI controller initializations */ + zynq_qspi_init_hw(xqspi); + ret = devm_spi_register_controller(&pdev->dev, ctlr); if (ret) { dev_err(&pdev->dev, "spi_register_master failed\n"); -- cgit From d575c9b7c8b4c5ddfb1aa75ac91fdcc20ce328c4 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Nov 2019 15:07:44 +0100 Subject: spi: zynq-qspi: Support two chip selects The Zynq QSPI controller features 2 CS. When the num-cs DT property is set to 2, the hardware will be initialized to support having two devices connected over each CS. In this case, both CS lines are driven by the state of the U_PAGE (upper page) bit. When unset, the lower page (CS0) is selected, otherwise it is the upper page (CS1). Change tested on a custom design featuring two SPI-NORs with different CS on the Zynq-7000 QSPI bus. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20191108140744.1734-8-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index e76f9c9738f0..17641157354d 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -114,8 +114,8 @@ */ #define ZYNQ_QSPI_MODEBITS (SPI_CPOL | SPI_CPHA) -/* Default number of chip selects */ -#define ZYNQ_QSPI_DEFAULT_NUM_CS 1 +/* Maximum number of chip selects */ +#define ZYNQ_QSPI_MAX_NUM_CS 2 /** * struct zynq_qspi - Defines qspi driver instance @@ -159,6 +159,7 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset, /** * zynq_qspi_init_hw - Initialize the hardware * @xqspi: Pointer to the zynq_qspi structure + * @num_cs: Number of connected CS (to enable dual memories if needed) * * The default settings of the QSPI controller's configurable parameters on * reset are @@ -176,7 +177,7 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset, * - Set the little endian mode of TX FIFO and * - Enable the QSPI controller */ -static void zynq_qspi_init_hw(struct zynq_qspi *xqspi) +static void zynq_qspi_init_hw(struct zynq_qspi *xqspi, unsigned int num_cs) { u32 config_reg; @@ -184,7 +185,12 @@ static void zynq_qspi_init_hw(struct zynq_qspi *xqspi) zynq_qspi_write(xqspi, ZYNQ_QSPI_IDIS_OFFSET, ZYNQ_QSPI_IXR_ALL_MASK); /* Disable linear mode as the boot loader may have used it */ - zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, 0); + config_reg = 0; + /* At the same time, enable dual mode if more than 1 CS is available */ + if (num_cs > 1) + config_reg |= ZYNQ_QSPI_LCFG_TWO_MEM; + + zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, config_reg); /* Clear the RX FIFO */ while (zynq_qspi_read(xqspi, ZYNQ_QSPI_STATUS_OFFSET) & @@ -286,6 +292,17 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert) struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); u32 config_reg; + /* Select the lower (CS0) or upper (CS1) memory */ + if (ctlr->num_chipselect > 1) { + config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET); + if (!spi->chip_select) + config_reg &= ~ZYNQ_QSPI_LCFG_U_PAGE; + else + config_reg |= ZYNQ_QSPI_LCFG_U_PAGE; + + zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, config_reg); + } + /* Ground the line to assert the CS */ config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET); if (assert) @@ -673,9 +690,9 @@ static int zynq_qspi_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "num-cs", &num_cs); if (ret < 0) { - ctlr->num_chipselect = ZYNQ_QSPI_DEFAULT_NUM_CS; - } else if (num_cs > ZYNQ_QSPI_DEFAULT_NUM_CS) { - dev_err(&pdev->dev, "anything but CS0 is not yet supported\n"); + ctlr->num_chipselect = 1; + } else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) { + dev_err(&pdev->dev, "only 2 chip selects are available\n"); goto remove_master; } else { ctlr->num_chipselect = num_cs; @@ -689,7 +706,7 @@ static int zynq_qspi_probe(struct platform_device *pdev) ctlr->dev.of_node = np; /* QSPI controller initializations */ - zynq_qspi_init_hw(xqspi); + zynq_qspi_init_hw(xqspi, ctlr->num_chipselect); ret = devm_spi_register_controller(&pdev->dev, ctlr); if (ret) { -- cgit From 8d8584912a4348ca41653dca70f2099a82e644d9 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Sat, 9 Nov 2019 09:48:27 +0530 Subject: spi: omap2-mcspi: Remove redundant checks Both omap2_mcspi_tx_dma() and omap2_mcspi_rx_dma() are only called from omap2_mcspi_txrx_dma() and omap2_mcspi_txrx_dma() is always called after making sure that mcspi_dma->dma_rx and mcspi_dma->dma_tx are not NULL (see omap2_mcspi_transfer_one()). Therefore remove redundant NULL checks for omap2_mcspi->dma_tx and omap2_mcspi->dma_rx pointers in omap2_mcspi_tx_dma() and omap2_mcspi_rx_dma() respectively. Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20191109041827.26934-1-vigneshr@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 105 +++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 58 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 848e03e5f42d..7e2292c11d12 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -397,30 +397,26 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi, { struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; + struct dma_async_tx_descriptor *tx; mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; - if (mcspi_dma->dma_tx) { - struct dma_async_tx_descriptor *tx; + dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); - dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); - - tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl, - xfer->tx_sg.nents, - DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (tx) { - tx->callback = omap2_mcspi_tx_callback; - tx->callback_param = spi; - dmaengine_submit(tx); - } else { - /* FIXME: fall back to PIO? */ - } + tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl, + xfer->tx_sg.nents, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (tx) { + tx->callback = omap2_mcspi_tx_callback; + tx->callback_param = spi; + dmaengine_submit(tx); + } else { + /* FIXME: fall back to PIO? */ } dma_async_issue_pending(mcspi_dma->dma_tx); omap2_mcspi_set_dma_req(spi, 0, 1); - } static unsigned @@ -439,6 +435,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, int word_len, element_count; struct omap2_mcspi_cs *cs = spi->controller_state; void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; + struct dma_async_tx_descriptor *tx; mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; @@ -462,55 +459,47 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, else /* word_len <= 32 */ element_count = count >> 2; - if (mcspi_dma->dma_rx) { - struct dma_async_tx_descriptor *tx; - dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); + dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); + /* + * Reduce DMA transfer length by one more if McSPI is + * configured in turbo mode. + */ + if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) + transfer_reduction += es; + + if (transfer_reduction) { + /* Split sgl into two. The second sgl won't be used. */ + sizes[0] = count - transfer_reduction; + sizes[1] = transfer_reduction; + nb_sizes = 2; + } else { /* - * Reduce DMA transfer length by one more if McSPI is - * configured in turbo mode. + * Don't bother splitting the sgl. This essentially + * clones the original sgl. */ - if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) - transfer_reduction += es; - - if (transfer_reduction) { - /* Split sgl into two. The second sgl won't be used. */ - sizes[0] = count - transfer_reduction; - sizes[1] = transfer_reduction; - nb_sizes = 2; - } else { - /* - * Don't bother splitting the sgl. This essentially - * clones the original sgl. - */ - sizes[0] = count; - nb_sizes = 1; - } + sizes[0] = count; + nb_sizes = 1; + } - ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, - 0, nb_sizes, - sizes, - sg_out, out_mapped_nents, - GFP_KERNEL); + ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes, + sizes, sg_out, out_mapped_nents, GFP_KERNEL); - if (ret < 0) { - dev_err(&spi->dev, "sg_split failed\n"); - return 0; - } + if (ret < 0) { + dev_err(&spi->dev, "sg_split failed\n"); + return 0; + } - tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, - sg_out[0], - out_mapped_nents[0], - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (tx) { - tx->callback = omap2_mcspi_rx_callback; - tx->callback_param = spi; - dmaengine_submit(tx); - } else { - /* FIXME: fall back to PIO? */ - } + tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0], + out_mapped_nents[0], DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (tx) { + tx->callback = omap2_mcspi_rx_callback; + tx->callback_param = spi; + dmaengine_submit(tx); + } else { + /* FIXME: fall back to PIO? */ } dma_async_issue_pending(mcspi_dma->dma_rx); -- cgit From 69c23dbf5f695c219008257b3bd86cff63edbe0b Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Sat, 9 Nov 2019 15:55:17 +0800 Subject: spi: nxp-fspi: Use devm API to fix missed unregistration of controller This driver forgets to unregister controller when remove. Use devm API to unregister it automatically to fix it. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191109075517.29988-1-hslester96@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-nxp-fspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 501b923f2c27..c36bb1bb464e 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -1027,7 +1027,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) ctlr->dev.of_node = np; - ret = spi_register_controller(ctlr); + ret = devm_spi_register_controller(&pdev->dev, ctlr); if (ret) goto err_destroy_mutex; -- cgit From 5eb263ef08b5014cfc2539a838f39d2fd3531423 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Sat, 9 Nov 2019 16:09:43 +0800 Subject: spi: pxa2xx: Add missed security checks pxa2xx_spi_init_pdata misses checks for devm_clk_get and platform_get_irq. Add checks for them to fix the bugs. Since ssp->clk and ssp->irq are used in probe, they are mandatory here. So we cannot use _optional() for devm_clk_get and platform_get_irq. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191109080943.30428-1-hslester96@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 6eb6805ee51d..9bc710c1b9e5 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1557,7 +1557,13 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) #endif ssp->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ssp->clk)) + return NULL; + ssp->irq = platform_get_irq(pdev, 0); + if (ssp->irq < 0) + return NULL; + ssp->type = type; ssp->dev = &pdev->dev; ssp->port_id = pxa2xx_spi_get_port_id(&pdev->dev); -- cgit From 57a9460705f105e1d79d1410c5cfe285beda8986 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 11 Nov 2019 11:53:34 -0800 Subject: spi: Fix regression to return zero on success instead of positive value Commit d948e6ca1899 ("spi: add power control when set_cs") added generic runtime PM handling, but also changed the return value to be 1 instead of 0 that we had earlier as pm_runtime_get functions return a positve value on success. This causes SPI devices to return errors for cases where they do: ret = spi_setup(spi); if (ret) return ret; As in many cases the SPI devices do not check for if (ret < 0). Let's fix this by setting the status to 0 on succeess after the runtime PM calls. Let's not return 0 at the end of the function as this might break again later on if the function changes and starts returning status again. Fixes: d948e6ca1899 ("spi: add power control when set_cs") Cc: Luhua Xu Cc: wsd_upstream@mediatek.com Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20191111195334.44833-1-tony@atomide.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 294d0038eea6..0d40953b463c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3269,6 +3269,15 @@ int spi_setup(struct spi_device *spi) status); return status; } + + /* + * We do not want to return positive value from pm_runtime_get, + * there are many instances of devices calling spi_setup() and + * checking for a non-zero return value instead of a negative + * return value. + */ + status = 0; + spi_set_cs(spi, false); pm_runtime_mark_last_busy(spi->controller->dev.parent); pm_runtime_put_autosuspend(spi->controller->dev.parent); -- cgit From cef76e5ace759848e78323a14df0dcd66b8de13d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:48 +0200 Subject: spi: at91-usart: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Acked-by: Nicolas Ferre Link: https://lore.kernel.org/r/20191113094256.1108-2-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-at91-usart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index a40bb2ef89dc..88033422a42a 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -132,7 +132,7 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - ctlr->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + ctlr->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR_OR_NULL(ctlr->dma_tx)) { if (IS_ERR(ctlr->dma_tx)) { err = PTR_ERR(ctlr->dma_tx); @@ -145,7 +145,7 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr, goto at91_usart_spi_error_clear; } - ctlr->dma_rx = dma_request_slave_channel_reason(dev, "rx"); + ctlr->dma_rx = dma_request_chan(dev, "rx"); if (IS_ERR_OR_NULL(ctlr->dma_rx)) { if (IS_ERR(ctlr->dma_rx)) { err = PTR_ERR(ctlr->dma_rx); -- cgit From bef1e0c8f74c87e7427cb98b2e76caf046c7b65a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:49 +0200 Subject: spi: atmel: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Acked-by: Nicolas Ferre Link: https://lore.kernel.org/r/20191113094256.1108-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index d88e2aa64839..d692cc388126 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -512,7 +512,7 @@ static int atmel_spi_configure_dma(struct spi_master *master, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + master->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(master->dma_tx)) { err = PTR_ERR(master->dma_tx); if (err == -EPROBE_DEFER) { -- cgit From 2e33f310dcfbceb7492d7e88baa9ca4f056f7c40 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:50 +0200 Subject: spi: fsl-lpspi: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191113094256.1108-4-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 6f4769a53f8a..2cc0ddb4a988 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -675,7 +675,7 @@ static int fsl_lpspi_dma_init(struct device *dev, int ret; /* Prepare for TX DMA: */ - controller->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + controller->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(controller->dma_tx)) { ret = PTR_ERR(controller->dma_tx); dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret); @@ -684,7 +684,7 @@ static int fsl_lpspi_dma_init(struct device *dev, } /* Prepare for RX DMA: */ - controller->dma_rx = dma_request_slave_channel_reason(dev, "rx"); + controller->dma_rx = dma_request_chan(dev, "rx"); if (IS_ERR(controller->dma_rx)) { ret = PTR_ERR(controller->dma_rx); dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret); -- cgit From 5d3aa9ccf40cdc9b94d1a708d11de9062e2d9eed Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:51 +0200 Subject: spi: imx: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191113094256.1108-5-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 09c9a1edb2c6..49f0099db0cb 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1272,7 +1272,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, spi_imx->wml = spi_imx->devtype_data->fifo_size / 2; /* Prepare for TX DMA: */ - master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + master->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(master->dma_tx)) { ret = PTR_ERR(master->dma_tx); dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret); @@ -1281,7 +1281,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, } /* Prepare for RX : */ - master->dma_rx = dma_request_slave_channel_reason(dev, "rx"); + master->dma_rx = dma_request_chan(dev, "rx"); if (IS_ERR(master->dma_rx)) { ret = PTR_ERR(master->dma_rx); dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret); -- cgit From c1008957ff1aee0ac92c28c55947173fb68cd451 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:52 +0200 Subject: spi: pl022: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20191113094256.1108-6-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 3024c30e7f2e..66028ebbc336 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1158,7 +1158,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022) int err; /* automatically configure DMA channels from platform, normally using DT */ - chan = dma_request_slave_channel_reason(dev, "rx"); + chan = dma_request_chan(dev, "rx"); if (IS_ERR(chan)) { err = PTR_ERR(chan); goto err_no_rxchan; @@ -1166,7 +1166,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022) pl022->dma_rx_channel = chan; - chan = dma_request_slave_channel_reason(dev, "tx"); + chan = dma_request_chan(dev, "tx"); if (IS_ERR(chan)) { err = PTR_ERR(chan); goto err_no_txchan; -- cgit From 194e1d4bc262c2d23ba9a8a5c03855c372ea1b5c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:53 +0200 Subject: spi: qup: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191113094256.1108-7-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 2f559e531100..dd3434a407ea 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -932,11 +932,11 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base) int ret; /* allocate dma resources, if available */ - master->dma_rx = dma_request_slave_channel_reason(dev, "rx"); + master->dma_rx = dma_request_chan(dev, "rx"); if (IS_ERR(master->dma_rx)) return PTR_ERR(master->dma_rx); - master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + master->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(master->dma_tx)) { ret = PTR_ERR(master->dma_tx); goto err_tx; -- cgit From df1b0141788527c032a9851c0589a1712d7e46b8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:54 +0200 Subject: spi: s3c64xx: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Acked-by: Krzysztof Kozlowski Acked-by: Andi Shyti Link: https://lore.kernel.org/r/20191113094256.1108-8-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 7b7151ec14c8..cf67ea60dc0e 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1154,15 +1154,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) if (!is_polling(sdd)) { /* Acquire DMA channels */ - sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, - "rx"); + sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx"); if (IS_ERR(sdd->rx_dma.ch)) { dev_err(&pdev->dev, "Failed to get RX DMA channel\n"); ret = PTR_ERR(sdd->rx_dma.ch); goto err_disable_io_clk; } - sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, - "tx"); + sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx"); if (IS_ERR(sdd->tx_dma.ch)) { dev_err(&pdev->dev, "Failed to get TX DMA channel\n"); ret = PTR_ERR(sdd->tx_dma.ch); -- cgit From 4c973b98cdd3b413216fdb9655a420737c46a4cb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:55 +0200 Subject: spi: tegra114: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Acked-by: Jon Hunter Link: https://lore.kernel.org/r/20191113094256.1108-9-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e6a450d9b4f0..fc40ab146c86 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -666,8 +666,7 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, dma_addr_t dma_phys; int ret; - dma_chan = dma_request_slave_channel_reason(tspi->dev, - dma_to_memory ? "rx" : "tx"); + dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx"); if (IS_ERR(dma_chan)) { ret = PTR_ERR(dma_chan); if (ret != -EPROBE_DEFER) -- cgit From 912a7df474d2cb22fc99a1fcf77997f2cea7d85e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:42:56 +0200 Subject: spi: tegra20-slink: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Acked-by: Jon Hunter Link: https://lore.kernel.org/r/20191113094256.1108-10-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 111fffc91435..51573f41ed12 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -599,8 +599,7 @@ static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi, int ret; struct dma_slave_config dma_sconfig; - dma_chan = dma_request_slave_channel_reason(tspi->dev, - dma_to_memory ? "rx" : "tx"); + dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx"); if (IS_ERR(dma_chan)) { ret = PTR_ERR(dma_chan); if (ret != -EPROBE_DEFER) -- cgit From 04358e40ba96d687c0811c21d9dede73f5244a98 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Fri, 15 Nov 2019 16:31:22 +0800 Subject: spi: tegra20-slink: add missed clk_unprepare The driver misses calling clk_unprepare in probe failure and remove. Add the calls to fix it. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191115083122.12278-1-hslester96@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 51573f41ed12..7f4d932dade7 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1072,7 +1072,7 @@ static int tegra_slink_probe(struct platform_device *pdev) ret = clk_enable(tspi->clk); if (ret < 0) { dev_err(&pdev->dev, "Clock enable failed %d\n", ret); - goto exit_free_master; + goto exit_clk_unprepare; } spi_irq = platform_get_irq(pdev, 0); @@ -1145,6 +1145,8 @@ exit_free_irq: free_irq(spi_irq, tspi); exit_clk_disable: clk_disable(tspi->clk); +exit_clk_unprepare: + clk_unprepare(tspi->clk); exit_free_master: spi_master_put(master); return ret; @@ -1158,6 +1160,7 @@ static int tegra_slink_remove(struct platform_device *pdev) free_irq(tspi->irq, tspi); clk_disable(tspi->clk); + clk_unprepare(tspi->clk); if (tspi->tx_dma_chan) tegra_slink_deinit_dma_param(tspi, false); -- cgit From cd050abeba2a95fe5374eec28ad2244617bcbab6 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Mon, 18 Nov 2019 10:48:48 +0800 Subject: spi: st-ssc4: add missed pm_runtime_disable The driver forgets to call pm_runtime_disable in probe failure and remove. Add the missed calls to fix it. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191118024848.21645-1-hslester96@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-st-ssc4.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index 0c24c494f386..77d26d64541a 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -381,6 +381,7 @@ static int spi_st_probe(struct platform_device *pdev) return 0; clk_disable: + pm_runtime_disable(&pdev->dev); clk_disable_unprepare(spi_st->clk); put_master: spi_master_put(master); @@ -392,6 +393,8 @@ static int spi_st_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct spi_st *spi_st = spi_master_get_devdata(master); + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(spi_st->clk); pinctrl_pm_select_sleep_state(&pdev->dev); -- cgit From ae7c2d342a10dbef1e054482f46498b6282a1df0 Mon Sep 17 00:00:00 2001 From: Luhua Xu Date: Mon, 18 Nov 2019 12:57:16 +0800 Subject: spi: mediatek: add SPI_CS_HIGH support Change to use SPI_CS_HIGH to support spi CS polarity setting for chips support enhance_timing. Signed-off-by: Luhua Xu Link: https://lore.kernel.org/r/1574053037-26721-2-git-send-email-luhua.xu@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 25fe149a8d9a..6783e12c40c2 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -139,7 +139,6 @@ static const struct mtk_spi_compatible mt8183_compat = { * supplies it. */ static const struct mtk_chip_config mtk_default_chip_info = { - .cs_pol = 0, .sample_sel = 0, }; @@ -230,10 +229,12 @@ static int mtk_spi_prepare_message(struct spi_master *master, #endif if (mdata->dev_comp->enhance_timing) { - if (chip_config->cs_pol) + /* set CS polarity */ + if (spi->mode & SPI_CS_HIGH) reg_val |= SPI_CMD_CS_POL; else reg_val &= ~SPI_CMD_CS_POL; + if (chip_config->sample_sel) reg_val |= SPI_CMD_SAMPLE_SEL; else @@ -264,6 +265,9 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable) u32 reg_val; struct mtk_spi *mdata = spi_master_get_devdata(spi->master); + if (spi->mode & SPI_CS_HIGH) + enable = !enable; + reg_val = readl(mdata->base + SPI_CMD_REG); if (!enable) { reg_val |= SPI_CMD_PAUSE_EN; @@ -646,6 +650,10 @@ static int mtk_spi_probe(struct platform_device *pdev) mdata = spi_master_get_devdata(master); mdata->dev_comp = of_id->data; + + if (mdata->dev_comp->enhance_timing) + master->mode_bits |= SPI_CS_HIGH; + if (mdata->dev_comp->must_tx) master->flags = SPI_MASTER_MUST_TX; -- cgit From 554bbe726ce0ef692cd95fedd5730c69c1189138 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 20 Nov 2019 21:39:16 +0800 Subject: spi: Fix Kconfig indentation Adjust indentation from spaces to tab (+optional two spaces) as in coding style with command like: $ sed -e 's/^ /\t/' -i */Kconfig Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20191120133916.13595-1-krzk@kernel.org Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6c0c1f55bd71..870f7797b56b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -144,7 +144,7 @@ config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" depends on BCM63XX || COMPILE_TEST help - Enable support for the SPI controller on the Broadcom BCM63xx SoCs. + Enable support for the SPI controller on the Broadcom BCM63xx SoCs. config SPI_BCM63XX_HSSPI tristate "Broadcom BCM63XX HS SPI controller driver" @@ -235,11 +235,11 @@ config SPI_DLN2 tristate "Diolan DLN-2 USB SPI adapter" depends on MFD_DLN2 help - If you say yes to this option, support will be included for Diolan - DLN2, a USB to SPI interface. + If you say yes to this option, support will be included for Diolan + DLN2, a USB to SPI interface. - This driver can also be built as a module. If so, the module - will be called spi-dln2. + This driver can also be built as a module. If so, the module + will be called spi-dln2. config SPI_EFM32 tristate "EFM32 SPI controller" @@ -748,10 +748,10 @@ config SPI_SYNQUACER It also supports the new dual-bit and quad-bit SPI protocol. config SPI_MXIC - tristate "Macronix MX25F0A SPI controller" - depends on SPI_MASTER - help - This selects the Macronix MX25F0A SPI controller driver. + tristate "Macronix MX25F0A SPI controller" + depends on SPI_MASTER + help + This selects the Macronix MX25F0A SPI controller driver. config SPI_MXS tristate "Freescale MXS SPI controller" -- cgit From eb7e6dc6d9ffcce129ac04d4e7bd2dc015bd45a5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 21 Nov 2019 11:27:03 +0200 Subject: spi: pic32: Retire dma_request_slave_channel_compat() There is no reason to use the dma_request_slave_channel_compat() as no filter function and parameter is provided. Switch the driver to use dma_request_chan() instead and add support for deferred probing against DMA channel. Signed-off-by: Peter Ujfalusi Reviewed-by: Vinod Koul Link: https://lore.kernel.org/r/20191121092703.30465-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-pic32.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index 69f517ec59c6..156961b4ca86 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -606,25 +606,30 @@ static void pic32_spi_cleanup(struct spi_device *spi) gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); } -static void pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev) +static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev) { struct spi_master *master = pic32s->master; - dma_cap_mask_t mask; + int ret = 0; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + master->dma_rx = dma_request_chan(dev, "spi-rx"); + if (IS_ERR(master->dma_rx)) { + if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) + ret = -EPROBE_DEFER; + else + dev_warn(dev, "RX channel not found.\n"); - master->dma_rx = dma_request_slave_channel_compat(mask, NULL, NULL, - dev, "spi-rx"); - if (!master->dma_rx) { - dev_warn(dev, "RX channel not found.\n"); + master->dma_rx = NULL; goto out_err; } - master->dma_tx = dma_request_slave_channel_compat(mask, NULL, NULL, - dev, "spi-tx"); - if (!master->dma_tx) { - dev_warn(dev, "TX channel not found.\n"); + master->dma_tx = dma_request_chan(dev, "spi-tx"); + if (IS_ERR(master->dma_tx)) { + if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) + ret = -EPROBE_DEFER; + else + dev_warn(dev, "TX channel not found.\n"); + + master->dma_tx = NULL; goto out_err; } @@ -634,14 +639,20 @@ static void pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev) /* DMA chnls allocated and prepared */ set_bit(PIC32F_DMA_PREP, &pic32s->flags); - return; + return 0; out_err: - if (master->dma_rx) + if (master->dma_rx) { dma_release_channel(master->dma_rx); + master->dma_rx = NULL; + } - if (master->dma_tx) + if (master->dma_tx) { dma_release_channel(master->dma_tx); + master->dma_tx = NULL; + } + + return ret; } static void pic32_spi_dma_unprep(struct pic32_spi *pic32s) @@ -776,7 +787,10 @@ static int pic32_spi_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = pic32_spi_unprepare_hardware; /* optional DMA support */ - pic32_spi_dma_prep(pic32s, &pdev->dev); + ret = pic32_spi_dma_prep(pic32s, &pdev->dev); + if (ret) + goto err_bailout; + if (test_bit(PIC32F_DMA_PREP, &pic32s->flags)) master->can_dma = pic32_spi_can_dma; -- cgit