diff options
author | Mark Brown <broonie@kernel.org> | 2020-12-11 17:49:01 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-12-11 17:49:01 +0000 |
commit | 3e98a021cc85e7d52acdd1eae8a988e975ec5bf9 (patch) | |
tree | cecfac58b9550a602555a02a9d583ed0f3378b38 /drivers/spi | |
parent | 58f7553fa424fd0fd74e8b796d50c66014cebebe (diff) | |
parent | 2fee9583198eb97b5351feda7bd825e0f778385c (diff) | |
download | linux-3e98a021cc85e7d52acdd1eae8a988e975ec5bf9.tar.gz linux-3e98a021cc85e7d52acdd1eae8a988e975ec5bf9.tar.bz2 linux-3e98a021cc85e7d52acdd1eae8a988e975ec5bf9.zip |
Merge remote-tracking branch 'spi/for-5.11' into spi-next
Diffstat (limited to 'drivers/spi')
39 files changed, 423 insertions, 220 deletions
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 8c009c175f2c..10bc5390ab91 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -365,10 +365,14 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq, if (dummy_cycles) ifr |= QSPI_IFR_NBDUM(dummy_cycles); - /* Set data enable */ - if (op->data.nbytes) + /* Set data enable and data transfer type. */ + if (op->data.nbytes) { ifr |= QSPI_IFR_DATAEN; + if (op->addr.nbytes) + ifr |= QSPI_IFR_TFRTYP_MEM; + } + /* * If the QSPI controller is set in regular SPI mode, set it in * Serial Memory Mode (SMM). @@ -381,27 +385,24 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq, /* Clear pending interrupts */ (void)atmel_qspi_read(aq, QSPI_SR); - if (aq->caps->has_ricr) { - if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN) - ifr |= QSPI_IFR_APBTFRTYP_READ; - - /* Set QSPI Instruction Frame registers */ + /* Set QSPI Instruction Frame registers. */ + if (op->addr.nbytes && !op->data.nbytes) atmel_qspi_write(iar, aq, QSPI_IAR); + + if (aq->caps->has_ricr) { if (op->data.dir == SPI_MEM_DATA_IN) atmel_qspi_write(icr, aq, QSPI_RICR); else atmel_qspi_write(icr, aq, QSPI_WICR); - atmel_qspi_write(ifr, aq, QSPI_IFR); } else { - if (op->data.dir == SPI_MEM_DATA_OUT) + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR; - /* Set QSPI Instruction Frame registers */ - atmel_qspi_write(iar, aq, QSPI_IAR); atmel_qspi_write(icr, aq, QSPI_ICR); - atmel_qspi_write(ifr, aq, QSPI_IFR); } + atmel_qspi_write(ifr, aq, QSPI_IFR); + return 0; } @@ -535,7 +536,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) struct resource *res; int irq, err = 0; - ctrl = spi_alloc_master(&pdev->dev, sizeof(*aq)); + ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*aq)); if (!ctrl) return -ENOMEM; @@ -557,8 +558,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) aq->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(aq->regs)) { dev_err(&pdev->dev, "missing registers\n"); - err = PTR_ERR(aq->regs); - goto exit; + return PTR_ERR(aq->regs); } /* Map the AHB memory */ @@ -566,8 +566,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) aq->mem = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(aq->mem)) { dev_err(&pdev->dev, "missing AHB memory\n"); - err = PTR_ERR(aq->mem); - goto exit; + return PTR_ERR(aq->mem); } aq->mmap_size = resource_size(res); @@ -579,22 +578,21 @@ static int atmel_qspi_probe(struct platform_device *pdev) if (IS_ERR(aq->pclk)) { dev_err(&pdev->dev, "missing peripheral clock\n"); - err = PTR_ERR(aq->pclk); - goto exit; + return PTR_ERR(aq->pclk); } /* Enable the peripheral clock */ err = clk_prepare_enable(aq->pclk); if (err) { dev_err(&pdev->dev, "failed to enable the peripheral clock\n"); - goto exit; + return err; } aq->caps = of_device_get_match_data(&pdev->dev); if (!aq->caps) { dev_err(&pdev->dev, "Could not retrieve QSPI caps\n"); err = -EINVAL; - goto exit; + goto disable_pclk; } if (aq->caps->has_qspick) { @@ -638,8 +636,6 @@ disable_qspick: clk_disable_unprepare(aq->qspick); disable_pclk: clk_disable_unprepare(aq->pclk); -exit: - spi_controller_put(ctrl); return err; } diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 7f629544060d..3cf76096a76d 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -250,7 +250,6 @@ static int amd_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct spi_master *master; struct amd_spi *amd_spi; - struct resource *res; int err = 0; /* Allocate storage for spi_master and driver private data */ @@ -261,9 +260,7 @@ static int amd_spi_probe(struct platform_device *pdev) } amd_spi = spi_master_get_devdata(master); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - amd_spi->io_remap_addr = devm_ioremap_resource(&pdev->dev, res); + amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(amd_spi->io_remap_addr)) { err = PTR_ERR(amd_spi->io_remap_addr); dev_err(dev, "error %d ioremap of SPI registers failed\n", err); diff --git a/drivers/spi/spi-ar934x.c b/drivers/spi/spi-ar934x.c index d08dec09d423..def32e0aaefe 100644 --- a/drivers/spi/spi-ar934x.c +++ b/drivers/spi/spi-ar934x.c @@ -176,10 +176,11 @@ static int ar934x_spi_probe(struct platform_device *pdev) if (ret) return ret; - ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp)); + ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp)); if (!ctlr) { dev_info(&pdev->dev, "failed to allocate spi controller\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_clk_disable; } /* disable flash mapping and expose spi controller registers */ @@ -202,7 +203,13 @@ static int ar934x_spi_probe(struct platform_device *pdev) sp->clk_freq = clk_get_rate(clk); sp->ctlr = ctlr; - return devm_spi_register_controller(&pdev->dev, ctlr); + ret = spi_register_controller(ctlr); + if (!ret) + return 0; + +err_clk_disable: + clk_disable_unprepare(clk); + return ret; } static int ar934x_spi_remove(struct platform_device *pdev) @@ -213,6 +220,7 @@ static int ar934x_spi_remove(struct platform_device *pdev) ctlr = dev_get_drvdata(&pdev->dev); sp = spi_controller_get_devdata(ctlr); + spi_unregister_controller(ctlr); clk_disable_unprepare(sp->clk); return 0; diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 0e5e64a80848..948396b382d7 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -512,8 +512,8 @@ static int atmel_spi_configure_dma(struct spi_master *master, master->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(master->dma_tx)) { - err = dev_err_probe(dev, PTR_ERR(master->dma_tx), - "No TX DMA channel, DMA is disabled\n"); + err = PTR_ERR(master->dma_tx); + dev_dbg(dev, "No TX DMA channel, DMA is disabled\n"); goto error_clear; } @@ -524,7 +524,7 @@ static int atmel_spi_configure_dma(struct spi_master *master, * No reason to check EPROBE_DEFER here since we have already * requested tx channel. */ - dev_err(dev, "No RX DMA channel, DMA is disabled\n"); + dev_dbg(dev, "No RX DMA channel, DMA is disabled\n"); goto error; } diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 9909b18f3c5a..1f08d7553f07 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -494,8 +494,10 @@ static int bcm63xx_hsspi_resume(struct device *dev) if (bs->pll_clk) { ret = clk_prepare_enable(bs->pll_clk); - if (ret) + if (ret) { + clk_disable_unprepare(bs->clk); return ret; + } } spi_master_resume(master); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 818f2b22875d..7453a1dbbc06 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -1040,13 +1040,13 @@ static int davinci_spi_remove(struct platform_device *pdev) spi_bitbang_stop(&dspi->bitbang); clk_disable_unprepare(dspi->clk); - spi_master_put(master); if (dspi->dma_rx) { dma_release_channel(dspi->dma_rx); dma_release_channel(dspi->dma_tx); } + spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index c279b7891e3a..4aa8596fb1f2 100644 --- a/drivers/spi/spi-dw-bt1.c +++ b/drivers/spi/spi-dw-bt1.c @@ -217,7 +217,7 @@ static int dw_spi_bt1_sys_init(struct platform_device *pdev, if (mem) { dwsbt1->map = devm_ioremap_resource(&pdev->dev, mem); if (!IS_ERR(dwsbt1->map)) { - dwsbt1->map_len = (mem->end - mem->start + 1); + dwsbt1->map_len = resource_size(mem); dws->mem_ops.dirmap_create = dw_spi_bt1_dirmap_create; dws->mem_ops.dirmap_read = dw_spi_bt1_dirmap_read; } else { diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index c33866f747db..a305074c482e 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -137,14 +137,16 @@ static inline u32 rx_max(struct dw_spi *dws) static void dw_writer(struct dw_spi *dws) { u32 max = tx_max(dws); - u16 txw = 0; + u32 txw = 0; while (max--) { if (dws->tx) { if (dws->n_bytes == 1) txw = *(u8 *)(dws->tx); - else + else if (dws->n_bytes == 2) txw = *(u16 *)(dws->tx); + else + txw = *(u32 *)(dws->tx); dws->tx += dws->n_bytes; } @@ -156,15 +158,17 @@ static void dw_writer(struct dw_spi *dws) static void dw_reader(struct dw_spi *dws) { u32 max = rx_max(dws); - u16 rxw; + u32 rxw; while (max--) { rxw = dw_read_io_reg(dws, DW_SPI_DR); if (dws->rx) { if (dws->n_bytes == 1) *(u8 *)(dws->rx) = rxw; - else + else if (dws->n_bytes == 2) *(u16 *)(dws->rx) = rxw; + else + *(u32 *)(dws->rx) = rxw; dws->rx += dws->n_bytes; } @@ -311,8 +315,8 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, u32 speed_hz; u16 clk_div; - /* CTRLR0[ 4/3: 0] Data Frame Size */ - cr0 |= (cfg->dfs - 1); + /* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */ + cr0 |= (cfg->dfs - 1) << dws->dfs_offset; if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) /* CTRLR0[ 9:8] Transfer Mode */ @@ -828,6 +832,29 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws) dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len); } + /* + * Detect CTRLR0.DFS field size and offset by testing the lowest bits + * writability. Note DWC SSI controller also has the extended DFS, but + * with zero offset. + */ + if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) { + u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0); + + spi_enable_chip(dws, 0); + dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff); + cr0 = dw_readl(dws, DW_SPI_CTRLR0); + dw_writel(dws, DW_SPI_CTRLR0, tmp); + spi_enable_chip(dws, 1); + + if (!(cr0 & SPI_DFS_MASK)) { + dws->caps |= DW_SPI_CAP_DFS32; + dws->dfs_offset = SPI_DFS32_OFFSET; + dev_dbg(dev, "Detected 32-bits max data frame size\n"); + } + } else { + dws->caps |= DW_SPI_CAP_DFS32; + } + /* enable HW fixup for explicit CS deselect for Amazon's alpine chip */ if (dws->caps & DW_SPI_CAP_CS_OVERRIDE) dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF); @@ -864,7 +891,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); + if (dws->caps & DW_SPI_CAP_DFS32) + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + else + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; master->setup = dw_spi_setup; diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index d0cc5bf4fa4e..17c06039a74d 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -222,6 +222,21 @@ static int dw_spi_keembay_init(struct platform_device *pdev, return 0; } +static int dw_spi_canaan_k210_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) +{ + /* + * The Canaan Kendryte K210 SoC DW apb_ssi v4 spi controller is + * documented to have a 32 word deep TX and RX FIFO, which + * spi_hw_init() detects. However, when the RX FIFO is filled up to + * 32 entries (RXFLR = 32), an RX FIFO overrun error occurs. Avoid this + * problem by force setting fifo_len to 31. + */ + dwsmmio->dws.fifo_len = 31; + + return 0; +} + static int dw_spi_mmio_probe(struct platform_device *pdev) { int (*init_func)(struct platform_device *pdev, @@ -335,6 +350,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = { { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init}, { .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init}, { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init}, + { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init}, { /* end of table */} }; MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index faf40cb66498..b665e040862c 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -9,6 +9,7 @@ #include <linux/io.h> #include <linux/scatterlist.h> #include <linux/spi/spi-mem.h> +#include <linux/bitfield.h> /* Register offsets */ #define DW_SPI_CTRLR0 0x00 @@ -41,6 +42,8 @@ /* Bit fields in CTRLR0 */ #define SPI_DFS_OFFSET 0 +#define SPI_DFS_MASK GENMASK(3, 0) +#define SPI_DFS32_OFFSET 16 #define SPI_FRF_OFFSET 4 #define SPI_FRF_SPI 0x0 @@ -121,6 +124,7 @@ enum dw_ssi_type { #define DW_SPI_CAP_CS_OVERRIDE BIT(0) #define DW_SPI_CAP_KEEMBAY_MST BIT(1) #define DW_SPI_CAP_DWC_SSI BIT(2) +#define DW_SPI_CAP_DFS32 BIT(3) /* Slave spi_transfer/spi_mem_op related */ struct dw_spi_cfg { @@ -148,6 +152,7 @@ struct dw_spi { unsigned long paddr; int irq; u32 fifo_len; /* depth of the FIFO buffer */ + unsigned int dfs_offset; /* CTRLR0 DFS field offset */ u32 max_mem_freq; /* max mem-ops bus freq */ u32 max_freq; /* max bus freq supported */ diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 25810a7eef10..512e925d5ea4 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -603,7 +603,7 @@ static int spi_geni_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - spi = spi_alloc_master(dev, sizeof(*mas)); + spi = devm_spi_alloc_master(dev, sizeof(*mas)); if (!spi) return -ENOMEM; @@ -636,6 +636,7 @@ static int spi_geni_probe(struct platform_device *pdev) spi->auto_runtime_pm = true; spi->handle_err = handle_fifo_timeout; spi->set_cs = spi_geni_set_cs; + spi->use_gpio_descriptors = true; init_completion(&mas->cs_done); init_completion(&mas->cancel_done); @@ -673,7 +674,6 @@ spi_geni_probe_free_irq: free_irq(mas->irq, spi); spi_geni_probe_runtime_disable: pm_runtime_disable(dev); - spi_master_put(spi); dev_pm_opp_of_remove_table(&pdev->dev); put_clkname: dev_pm_opp_put_clkname(mas->se.opp_table); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 7ceb0ba27b75..0584f4d2fde2 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -350,11 +350,6 @@ static int spi_gpio_probe_pdata(struct platform_device *pdev, return 0; } -static void spi_gpio_put(void *data) -{ - spi_master_put(data); -} - static int spi_gpio_probe(struct platform_device *pdev) { int status; @@ -363,16 +358,10 @@ static int spi_gpio_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct spi_bitbang *bb; - master = spi_alloc_master(dev, sizeof(*spi_gpio)); + master = devm_spi_alloc_master(dev, sizeof(*spi_gpio)); if (!master) return -ENOMEM; - status = devm_add_action_or_reset(&pdev->dev, spi_gpio_put, master); - if (status) { - spi_master_put(master); - return status; - } - if (pdev->dev.of_node) status = spi_gpio_probe_dt(pdev, master); else @@ -432,7 +421,7 @@ static int spi_gpio_probe(struct platform_device *pdev) if (status) return status; - return devm_spi_register_master(&pdev->dev, spi_master_get(master)); + return devm_spi_register_master(&pdev->dev, master); } MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index b068537375d6..5f05d519fbbd 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -731,8 +731,10 @@ static int img_spfi_resume(struct device *dev) int ret; ret = pm_runtime_get_sync(dev); - if (ret) + if (ret) { + pm_runtime_put_noidle(dev); return ret; + } spfi_reset(spfi); pm_runtime_put(dev); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 0b597905ee72..73ca821763d6 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1019,33 +1019,6 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = { .devtype = IMX53_ECSPI, }; -static const struct platform_device_id spi_imx_devtype[] = { - { - .name = "imx1-cspi", - .driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data, - }, { - .name = "imx21-cspi", - .driver_data = (kernel_ulong_t) &imx21_cspi_devtype_data, - }, { - .name = "imx27-cspi", - .driver_data = (kernel_ulong_t) &imx27_cspi_devtype_data, - }, { - .name = "imx31-cspi", - .driver_data = (kernel_ulong_t) &imx31_cspi_devtype_data, - }, { - .name = "imx35-cspi", - .driver_data = (kernel_ulong_t) &imx35_cspi_devtype_data, - }, { - .name = "imx51-ecspi", - .driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data, - }, { - .name = "imx53-ecspi", - .driver_data = (kernel_ulong_t) &imx53_ecspi_devtype_data, - }, { - /* sentinel */ - } -}; - static const struct of_device_id spi_imx_dt_ids[] = { { .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, }, { .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, }, @@ -1538,6 +1511,7 @@ spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg) ret = pm_runtime_get_sync(spi_imx->dev); if (ret < 0) { + pm_runtime_put_noidle(spi_imx->dev); dev_err(spi_imx->dev, "failed to enable clock\n"); return ret; } @@ -1580,8 +1554,7 @@ static int spi_imx_probe(struct platform_device *pdev) struct spi_imx_data *spi_imx; struct resource *res; int ret, irq, spi_drctl; - const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data : - (struct spi_imx_devtype_data *)pdev->id_entry->driver_data; + const struct spi_imx_devtype_data *devtype_data = of_id->data; bool slave_mode; u32 val; @@ -1748,6 +1721,7 @@ static int spi_imx_remove(struct platform_device *pdev) ret = pm_runtime_get_sync(spi_imx->dev); if (ret < 0) { + pm_runtime_put_noidle(spi_imx->dev); dev_err(spi_imx->dev, "failed to enable clock\n"); return ret; } @@ -1822,7 +1796,6 @@ static struct platform_driver spi_imx_driver = { .of_match_table = spi_imx_dt_ids, .pm = &imx_spi_pm, }, - .id_table = spi_imx_devtype, .probe = spi_imx_probe, .remove = spi_imx_remove, }; diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index ef53290b7d24..f3a3f196e628 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -243,6 +243,7 @@ static int spi_mem_access_start(struct spi_mem *mem) ret = pm_runtime_get_sync(ctlr->dev.parent); if (ret < 0) { + pm_runtime_put_noidle(ctlr->dev.parent); dev_err(&ctlr->dev, "Failed to power device: %d\n", ret); return ret; @@ -743,7 +744,7 @@ static int spi_mem_probe(struct spi_device *spi) mem->name = dev_name(&spi->dev); if (IS_ERR_OR_NULL(mem->name)) - return PTR_ERR(mem->name); + return PTR_ERR_OR_ZERO(mem->name); spi_set_drvdata(spi, mem); diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c index 2c3b7a2a1ec7..b4b9b7309b5e 100644 --- a/drivers/spi/spi-mt7621.c +++ b/drivers/spi/spi-mt7621.c @@ -350,9 +350,10 @@ static int mt7621_spi_probe(struct platform_device *pdev) if (status) return status; - master = spi_alloc_master(&pdev->dev, sizeof(*rs)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(*rs)); if (!master) { dev_info(&pdev->dev, "master allocation failed\n"); + clk_disable_unprepare(clk); return -ENOMEM; } @@ -377,10 +378,15 @@ static int mt7621_spi_probe(struct platform_device *pdev) ret = device_reset(&pdev->dev); if (ret) { dev_err(&pdev->dev, "SPI reset failed!\n"); + clk_disable_unprepare(clk); return ret; } - return devm_spi_register_controller(&pdev->dev, master); + ret = spi_register_controller(master); + if (ret) + clk_disable_unprepare(clk); + + return ret; } static int mt7621_spi_remove(struct platform_device *pdev) @@ -391,6 +397,7 @@ static int mt7621_spi_remove(struct platform_device *pdev) master = dev_get_drvdata(&pdev->dev); rs = spi_controller_get_devdata(master); + spi_unregister_controller(master); clk_disable_unprepare(rs->clk); return 0; diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index b97f26a60cbe..2e2f36a2e385 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -103,6 +103,7 @@ struct mtk_nor { dma_addr_t buffer_dma; struct clk *spi_clk; struct clk *ctlr_clk; + struct clk *axi_clk; unsigned int spi_freq; bool wbuf_en; bool has_irq; @@ -672,6 +673,7 @@ static void mtk_nor_disable_clk(struct mtk_nor *sp) { clk_disable_unprepare(sp->spi_clk); clk_disable_unprepare(sp->ctlr_clk); + clk_disable_unprepare(sp->axi_clk); } static int mtk_nor_enable_clk(struct mtk_nor *sp) @@ -688,6 +690,13 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp) return ret; } + ret = clk_prepare_enable(sp->axi_clk); + if (ret) { + clk_disable_unprepare(sp->spi_clk); + clk_disable_unprepare(sp->ctlr_clk); + return ret; + } + return 0; } @@ -746,7 +755,7 @@ static int mtk_nor_probe(struct platform_device *pdev) struct spi_controller *ctlr; struct mtk_nor *sp; void __iomem *base; - struct clk *spi_clk, *ctlr_clk; + struct clk *spi_clk, *ctlr_clk, *axi_clk; int ret, irq; unsigned long dma_bits; @@ -762,13 +771,17 @@ static int mtk_nor_probe(struct platform_device *pdev) if (IS_ERR(ctlr_clk)) return PTR_ERR(ctlr_clk); + axi_clk = devm_clk_get_optional(&pdev->dev, "axi"); + if (IS_ERR(axi_clk)) + return PTR_ERR(axi_clk); + dma_bits = (unsigned long)of_device_get_match_data(&pdev->dev); if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits))) { dev_err(&pdev->dev, "failed to set dma mask(%lu)\n", dma_bits); return -EINVAL; } - ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp)); + ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp)); if (!ctlr) { dev_err(&pdev->dev, "failed to allocate spi controller\n"); return -ENOMEM; @@ -794,6 +807,7 @@ static int mtk_nor_probe(struct platform_device *pdev) sp->dev = &pdev->dev; sp->spi_clk = spi_clk; sp->ctlr_clk = ctlr_clk; + sp->axi_clk = axi_clk; sp->high_dma = (dma_bits > 32); sp->buffer = dmam_alloc_coherent(&pdev->dev, MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN, diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 8c630acb0110..96b418293bf2 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -529,7 +529,7 @@ static int mxic_spi_probe(struct platform_device *pdev) struct mxic_spi *mxic; int ret; - master = spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi)); if (!master) return -ENOMEM; @@ -574,15 +574,9 @@ static int mxic_spi_probe(struct platform_device *pdev) ret = spi_register_master(master); if (ret) { dev_err(&pdev->dev, "spi_register_master failed\n"); - goto err_put_master; + pm_runtime_disable(&pdev->dev); } - return 0; - -err_put_master: - spi_master_put(master); - pm_runtime_disable(&pdev->dev); - return ret; } diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 918918a9e049..435309b09227 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -607,6 +607,7 @@ static int mxs_spi_probe(struct platform_device *pdev) ret = pm_runtime_get_sync(ssp->dev); if (ret < 0) { + pm_runtime_put_noidle(ssp->dev); dev_err(ssp->dev, "runtime_get_sync failed\n"); goto out_pm_runtime_disable; } diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index 1cb9329de945..b62471ab6d7f 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -677,7 +677,7 @@ static int npcm_fiu_probe(struct platform_device *pdev) struct npcm_fiu_spi *fiu; void __iomem *regbase; struct resource *res; - int id; + int id, ret; ctrl = devm_spi_alloc_master(dev, sizeof(*fiu)); if (!ctrl) @@ -735,7 +735,11 @@ static int npcm_fiu_probe(struct platform_device *pdev) ctrl->num_chipselect = fiu->info->max_cs; ctrl->dev.of_node = dev->of_node; - return devm_spi_register_master(dev, ctrl); + ret = devm_spi_register_master(dev, ctrl); + if (ret) + clk_disable_unprepare(fiu->clk); + + return ret; } static int npcm_fiu_remove(struct platform_device *pdev) diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index 156961b4ca86..104bde153efd 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -839,6 +839,7 @@ static int pic32_spi_probe(struct platform_device *pdev) return 0; err_bailout: + pic32_spi_dma_unprep(pic32s); clk_disable_unprepare(pic32s->clk); err_master: spi_master_put(master); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 814268405ab0..bd2354fd438d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1496,6 +1496,11 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP }, + /* ADL-S */ + { PCI_VDEVICE(INTEL, 0x7aaa), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x7aab), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x7af9), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x7afb), LPSS_CNL_SSP }, /* CNL-LP */ { PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP }, @@ -1686,9 +1691,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } if (platform_info->is_slave) - controller = spi_alloc_slave(dev, sizeof(struct driver_data)); + controller = devm_spi_alloc_slave(dev, sizeof(*drv_data)); else - controller = spi_alloc_master(dev, sizeof(struct driver_data)); + controller = devm_spi_alloc_master(dev, sizeof(*drv_data)); if (!controller) { dev_err(&pdev->dev, "cannot alloc spi_controller\n"); @@ -1911,7 +1916,6 @@ out_error_dma_irq_alloc: free_irq(ssp->irq, drv_data); out_error_controller_alloc: - spi_controller_put(controller); pxa_ssp_free(ssp); return status; } diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 5eed88af6899..8863be370884 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -462,7 +462,7 @@ static int qcom_qspi_probe(struct platform_device *pdev) dev = &pdev->dev; - master = spi_alloc_master(dev, sizeof(*ctrl)); + master = devm_spi_alloc_master(dev, sizeof(*ctrl)); if (!master) return -ENOMEM; @@ -473,54 +473,49 @@ static int qcom_qspi_probe(struct platform_device *pdev) spin_lock_init(&ctrl->lock); ctrl->dev = dev; ctrl->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ctrl->base)) { - ret = PTR_ERR(ctrl->base); - goto exit_probe_master_put; - } + if (IS_ERR(ctrl->base)) + return PTR_ERR(ctrl->base); ctrl->clks = devm_kcalloc(dev, QSPI_NUM_CLKS, sizeof(*ctrl->clks), GFP_KERNEL); - if (!ctrl->clks) { - ret = -ENOMEM; - goto exit_probe_master_put; - } + if (!ctrl->clks) + return -ENOMEM; ctrl->clks[QSPI_CLK_CORE].id = "core"; ctrl->clks[QSPI_CLK_IFACE].id = "iface"; ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks); if (ret) - goto exit_probe_master_put; + return ret; ctrl->icc_path_cpu_to_qspi = devm_of_icc_get(dev, "qspi-config"); - if (IS_ERR(ctrl->icc_path_cpu_to_qspi)) { - ret = dev_err_probe(dev, PTR_ERR(ctrl->icc_path_cpu_to_qspi), - "Failed to get cpu path\n"); - goto exit_probe_master_put; - } + if (IS_ERR(ctrl->icc_path_cpu_to_qspi)) + return dev_err_probe(dev, PTR_ERR(ctrl->icc_path_cpu_to_qspi), + "Failed to get cpu path\n"); + /* Set BW vote for register access */ ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, Bps_to_icc(1000), Bps_to_icc(1000)); if (ret) { dev_err(ctrl->dev, "%s: ICC BW voting failed for cpu: %d\n", __func__, ret); - goto exit_probe_master_put; + return ret; } ret = icc_disable(ctrl->icc_path_cpu_to_qspi); if (ret) { dev_err(ctrl->dev, "%s: ICC disable failed for cpu: %d\n", __func__, ret); - goto exit_probe_master_put; + return ret; } ret = platform_get_irq(pdev, 0); if (ret < 0) - goto exit_probe_master_put; + return ret; ret = devm_request_irq(dev, ret, qcom_qspi_irq, IRQF_TRIGGER_HIGH, dev_name(dev), ctrl); if (ret) { dev_err(dev, "Failed to request irq %d\n", ret); - goto exit_probe_master_put; + return ret; } master->max_speed_hz = 300000000; @@ -537,10 +532,8 @@ static int qcom_qspi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core"); - if (IS_ERR(ctrl->opp_table)) { - ret = PTR_ERR(ctrl->opp_table); - goto exit_probe_master_put; - } + if (IS_ERR(ctrl->opp_table)) + return PTR_ERR(ctrl->opp_table); /* OPP table is optional */ ret = dev_pm_opp_of_add_table(&pdev->dev); if (ret && ret != -ENODEV) { @@ -562,9 +555,6 @@ static int qcom_qspi_probe(struct platform_device *pdev) exit_probe_put_clkname: dev_pm_opp_put_clkname(ctrl->opp_table); -exit_probe_master_put: - spi_master_put(master); - return ret; } diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c index 8aa51beb4ff3..9f97d18a05c1 100644 --- a/drivers/spi/spi-rb4xx.c +++ b/drivers/spi/spi-rb4xx.c @@ -143,7 +143,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev) if (IS_ERR(spi_base)) return PTR_ERR(spi_base); - master = spi_alloc_master(&pdev->dev, sizeof(*rbspi)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(*rbspi)); if (!master) return -ENOMEM; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 75a8a9428ff8..09d8e92400eb 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -160,6 +160,8 @@ #define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002 #define ROCKCHIP_SPI_VER2_TYPE2 0x00110002 +#define ROCKCHIP_AUTOSUSPEND_TIMEOUT 2000 + struct rockchip_spi { struct device *dev; @@ -715,6 +717,8 @@ static int rockchip_spi_probe(struct platform_device *pdev) goto err_disable_spiclk; } + pm_runtime_set_autosuspend_delay(&pdev->dev, ROCKCHIP_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index ed3e548227f4..3579675485a5 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -134,7 +134,7 @@ static int rpcif_spi_probe(struct platform_device *pdev) struct rpcif *rpc; int error; - ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc)); + ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*rpc)); if (!ctlr) return -ENOMEM; @@ -159,13 +159,8 @@ static int rpcif_spi_probe(struct platform_device *pdev) error = spi_register_controller(ctlr); if (error) { dev_err(&pdev->dev, "spi_register_controller failed\n"); - goto err_put_ctlr; + rpcif_disable_rpm(rpc); } - return 0; - -err_put_ctlr: - rpcif_disable_rpm(rpc); - spi_controller_put(ctlr); return error; } diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index ee0f3edf49cd..297c512069a5 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -238,13 +238,12 @@ static int sc18is602_probe(struct i2c_client *client, struct sc18is602_platform_data *pdata = dev_get_platdata(dev); struct sc18is602 *hw; struct spi_master *master; - int error; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) return -EINVAL; - master = spi_alloc_master(dev, sizeof(struct sc18is602)); + master = devm_spi_alloc_master(dev, sizeof(struct sc18is602)); if (!master) return -ENOMEM; @@ -298,15 +297,7 @@ static int sc18is602_probe(struct i2c_client *client, master->min_speed_hz = hw->freq / 128; master->max_speed_hz = hw->freq / 4; - error = devm_spi_register_master(dev, master); - if (error) - goto error_reg; - - return 0; - -error_reg: - spi_master_put(master); - return error; + return devm_spi_register_master(dev, master); } static const struct i2c_device_id sc18is602_id[] = { diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 20bdae5fdf3b..15123a8f41e1 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -440,7 +440,7 @@ static int spi_sh_probe(struct platform_device *pdev) if (irq < 0) return irq; - master = spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data)); if (master == NULL) { dev_err(&pdev->dev, "spi_alloc_master error.\n"); return -ENOMEM; @@ -458,16 +458,14 @@ static int spi_sh_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "No support width\n"); - ret = -ENODEV; - goto error1; + return -ENODEV; } ss->irq = irq; ss->master = master; ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (ss->addr == NULL) { dev_err(&pdev->dev, "ioremap error.\n"); - ret = -ENOMEM; - goto error1; + return -ENOMEM; } INIT_LIST_HEAD(&ss->queue); spin_lock_init(&ss->lock); @@ -477,7 +475,7 @@ static int spi_sh_probe(struct platform_device *pdev) ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss); if (ret < 0) { dev_err(&pdev->dev, "request_irq error\n"); - goto error1; + return ret; } master->num_chipselect = 2; @@ -496,9 +494,6 @@ static int spi_sh_probe(struct platform_device *pdev) error3: free_irq(irq, ss); - error1: - spi_master_put(master); - return ret; } diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index 635738f54c73..b41a75749b49 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -1010,6 +1010,7 @@ static int sprd_spi_remove(struct platform_device *pdev) ret = pm_runtime_get_sync(ss->dev); if (ret < 0) { + pm_runtime_put_noidle(ss->dev); dev_err(ss->dev, "failed to resume SPI controller\n"); return ret; } diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index 77d26d64541a..6c44dda9ee8c 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -375,13 +375,14 @@ static int spi_st_probe(struct platform_device *pdev) ret = devm_spi_register_master(&pdev->dev, master); if (ret) { dev_err(&pdev->dev, "Failed to register master\n"); - goto clk_disable; + goto rpm_disable; } return 0; -clk_disable: +rpm_disable: pm_runtime_disable(&pdev->dev); +clk_disable: clk_disable_unprepare(spi_st->clk); put_master: spi_master_put(master); diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index a900962b4336..947e6b9dc9f4 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -434,8 +434,10 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) int ret; ret = pm_runtime_get_sync(qspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(qspi->dev); return ret; + } mutex_lock(&qspi->lock); ret = stm32_qspi_send(mem, op); @@ -462,8 +464,10 @@ static int stm32_qspi_setup(struct spi_device *spi) return -EINVAL; ret = pm_runtime_get_sync(qspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(qspi->dev); return ret; + } presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 2cc850eb8922..471dedf3d339 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -2062,6 +2062,7 @@ static int stm32_spi_resume(struct device *dev) ret = pm_runtime_get_sync(dev); if (ret < 0) { + pm_runtime_put_noidle(dev); dev_err(dev, "Unable to power device:%d\n", ret); return ret; } diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 19238e1b76b4..cc8401980125 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -18,9 +18,12 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> +#include <linux/dmaengine.h> #include <linux/spi/spi.h> +#define SUN6I_AUTOSUSPEND_TIMEOUT 2000 + #define SUN6I_FIFO_DEPTH 128 #define SUN8I_FIFO_DEPTH 64 @@ -52,10 +55,12 @@ #define SUN6I_FIFO_CTL_REG 0x18 #define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK 0xff +#define SUN6I_FIFO_CTL_RF_DRQ_EN BIT(8) #define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS 0 #define SUN6I_FIFO_CTL_RF_RST BIT(15) #define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK 0xff #define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS 16 +#define SUN6I_FIFO_CTL_TF_DRQ_EN BIT(24) #define SUN6I_FIFO_CTL_TF_RST BIT(31) #define SUN6I_FIFO_STA_REG 0x1c @@ -83,6 +88,8 @@ struct sun6i_spi { struct spi_master *master; void __iomem *base_addr; + dma_addr_t dma_addr_rx; + dma_addr_t dma_addr_tx; struct clk *hclk; struct clk *mclk; struct reset_control *rstc; @@ -182,6 +189,68 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device *spi) return SUN6I_MAX_XFER_SIZE - 1; } +static int sun6i_spi_prepare_dma(struct sun6i_spi *sspi, + struct spi_transfer *tfr) +{ + struct dma_async_tx_descriptor *rxdesc, *txdesc; + struct spi_master *master = sspi->master; + + rxdesc = NULL; + if (tfr->rx_buf) { + struct dma_slave_config rxconf = { + .direction = DMA_DEV_TO_MEM, + .src_addr = sspi->dma_addr_rx, + .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .src_maxburst = 8, + }; + + dmaengine_slave_config(master->dma_rx, &rxconf); + + rxdesc = dmaengine_prep_slave_sg(master->dma_rx, + tfr->rx_sg.sgl, + tfr->rx_sg.nents, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!rxdesc) + return -EINVAL; + } + + txdesc = NULL; + if (tfr->tx_buf) { + struct dma_slave_config txconf = { + .direction = DMA_MEM_TO_DEV, + .dst_addr = sspi->dma_addr_tx, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .dst_maxburst = 8, + }; + + dmaengine_slave_config(master->dma_tx, &txconf); + + txdesc = dmaengine_prep_slave_sg(master->dma_tx, + tfr->tx_sg.sgl, + tfr->tx_sg.nents, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT); + if (!txdesc) { + if (rxdesc) + dmaengine_terminate_sync(master->dma_rx); + return -EINVAL; + } + } + + if (tfr->rx_buf) { + dmaengine_submit(rxdesc); + dma_async_issue_pending(master->dma_rx); + } + + if (tfr->tx_buf) { + dmaengine_submit(txdesc); + dma_async_issue_pending(master->dma_tx); + } + + return 0; +} + static int sun6i_spi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr) @@ -191,6 +260,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, unsigned int start, end, tx_time; unsigned int trig_level; unsigned int tx_len = 0, rx_len = 0; + bool use_dma; int ret = 0; u32 reg; @@ -201,6 +271,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, sspi->tx_buf = tfr->tx_buf; sspi->rx_buf = tfr->rx_buf; sspi->len = tfr->len; + use_dma = master->can_dma ? master->can_dma(master, spi, tfr) : false; /* Clear pending interrupts */ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0); @@ -209,16 +280,34 @@ static int sun6i_spi_transfer_one(struct spi_master *master, sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST); - /* - * Setup FIFO interrupt trigger level - * Here we choose 3/4 of the full fifo depth, as it's the hardcoded - * value used in old generation of Allwinner SPI controller. - * (See spi-sun4i.c) - */ - trig_level = sspi->fifo_depth / 4 * 3; - sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, - (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) | - (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS)); + reg = 0; + + if (!use_dma) { + /* + * Setup FIFO interrupt trigger level + * Here we choose 3/4 of the full fifo depth, as it's + * the hardcoded value used in old generation of Allwinner + * SPI controller. (See spi-sun4i.c) + */ + trig_level = sspi->fifo_depth / 4 * 3; + } else { + /* + * Setup FIFO DMA request trigger level + * We choose 1/2 of the full fifo depth, that value will + * be used as DMA burst length. + */ + trig_level = sspi->fifo_depth / 2; + + if (tfr->tx_buf) + reg |= SUN6I_FIFO_CTL_TF_DRQ_EN; + if (tfr->rx_buf) + reg |= SUN6I_FIFO_CTL_RF_DRQ_EN; + } + + reg |= (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) | + (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS); + + sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, reg); /* * Setup the transfer control register: Chip Select, @@ -300,16 +389,28 @@ static int sun6i_spi_transfer_one(struct spi_master *master, sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len); sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len); - /* Fill the TX FIFO */ - sun6i_spi_fill_fifo(sspi); + if (!use_dma) { + /* Fill the TX FIFO */ + sun6i_spi_fill_fifo(sspi); + } else { + ret = sun6i_spi_prepare_dma(sspi, tfr); + if (ret) { + dev_warn(&master->dev, + "%s: prepare DMA failed, ret=%d", + dev_name(&spi->dev), ret); + return ret; + } + } /* Enable the interrupts */ reg = SUN6I_INT_CTL_TC; - if (rx_len > sspi->fifo_depth) - reg |= SUN6I_INT_CTL_RF_RDY; - if (tx_len > sspi->fifo_depth) - reg |= SUN6I_INT_CTL_TF_ERQ; + if (!use_dma) { + if (rx_len > sspi->fifo_depth) + reg |= SUN6I_INT_CTL_RF_RDY; + if (tx_len > sspi->fifo_depth) + reg |= SUN6I_INT_CTL_TF_ERQ; + } sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg); @@ -332,6 +433,11 @@ static int sun6i_spi_transfer_one(struct spi_master *master, sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); + if (ret && use_dma) { + dmaengine_terminate_sync(master->dma_rx); + dmaengine_terminate_sync(master->dma_tx); + } + return ret; } @@ -422,10 +528,25 @@ static int sun6i_spi_runtime_suspend(struct device *dev) return 0; } +static bool sun6i_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct sun6i_spi *sspi = spi_master_get_devdata(master); + + /* + * If the number of spi words to transfer is less or equal than + * the fifo length we can just fill the fifo and wait for a single + * irq, so don't bother setting up dma + */ + return xfer->len > sspi->fifo_depth; +} + static int sun6i_spi_probe(struct platform_device *pdev) { struct spi_master *master; struct sun6i_spi *sspi; + struct resource *mem; int ret = 0, irq; master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi)); @@ -437,7 +558,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); sspi = spi_master_get_devdata(master); - sspi->base_addr = devm_platform_ioremap_resource(pdev, 0); + sspi->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(sspi->base_addr)) { ret = PTR_ERR(sspi->base_addr); goto err_free_master; @@ -494,6 +615,33 @@ static int sun6i_spi_probe(struct platform_device *pdev) goto err_free_master; } + master->dma_tx = dma_request_chan(&pdev->dev, "tx"); + if (IS_ERR(master->dma_tx)) { + /* Check tx to see if we need defer probing driver */ + if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_free_master; + } + dev_warn(&pdev->dev, "Failed to request TX DMA channel\n"); + master->dma_tx = NULL; + } + + master->dma_rx = dma_request_chan(&pdev->dev, "rx"); + if (IS_ERR(master->dma_rx)) { + if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_free_dma_tx; + } + dev_warn(&pdev->dev, "Failed to request RX DMA channel\n"); + master->dma_rx = NULL; + } + + if (master->dma_tx && master->dma_rx) { + sspi->dma_addr_tx = mem->start + SUN6I_TXDATA_REG; + sspi->dma_addr_rx = mem->start + SUN6I_RXDATA_REG; + master->can_dma = sun6i_spi_can_dma; + } + /* * This wake-up/shutdown pattern is to be able to have the * device woken up, even if runtime_pm is disabled @@ -501,12 +649,13 @@ static int sun6i_spi_probe(struct platform_device *pdev) ret = sun6i_spi_runtime_resume(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Couldn't resume the device\n"); - goto err_free_master; + goto err_free_dma_rx; } + pm_runtime_set_autosuspend_delay(&pdev->dev, SUN6I_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - pm_runtime_idle(&pdev->dev); ret = devm_spi_register_master(&pdev->dev, master); if (ret) { @@ -519,6 +668,12 @@ static int sun6i_spi_probe(struct platform_device *pdev) err_pm_disable: pm_runtime_disable(&pdev->dev); sun6i_spi_runtime_suspend(&pdev->dev); +err_free_dma_rx: + if (master->dma_rx) + dma_release_channel(master->dma_rx); +err_free_dma_tx: + if (master->dma_tx) + dma_release_channel(master->dma_tx); err_free_master: spi_master_put(master); return ret; @@ -526,8 +681,14 @@ err_free_master: static int sun6i_spi_remove(struct platform_device *pdev) { + struct spi_master *master = platform_get_drvdata(pdev); + pm_runtime_force_suspend(&pdev->dev); + if (master->dma_tx) + dma_release_channel(master->dma_tx); + if (master->dma_rx) + dma_release_channel(master->dma_rx); return 0; } diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c index 42e82dbe3d41..8cdca6ab8098 100644 --- a/drivers/spi/spi-synquacer.c +++ b/drivers/spi/spi-synquacer.c @@ -657,7 +657,8 @@ static int synquacer_spi_probe(struct platform_device *pdev) if (!master->max_speed_hz) { dev_err(&pdev->dev, "missing clock source\n"); - return -EINVAL; + ret = -EINVAL; + goto disable_clk; } master->min_speed_hz = master->max_speed_hz / 254; @@ -670,7 +671,7 @@ static int synquacer_spi_probe(struct platform_device *pdev) rx_irq = platform_get_irq(pdev, 0); if (rx_irq <= 0) { ret = rx_irq; - goto put_spi; + goto disable_clk; } snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx", dev_name(&pdev->dev)); @@ -678,13 +679,13 @@ static int synquacer_spi_probe(struct platform_device *pdev) 0, sspi->rx_irq_name, sspi); if (ret) { dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret); - goto put_spi; + goto disable_clk; } tx_irq = platform_get_irq(pdev, 1); if (tx_irq <= 0) { ret = tx_irq; - goto put_spi; + goto disable_clk; } snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx", dev_name(&pdev->dev)); @@ -692,7 +693,7 @@ static int synquacer_spi_probe(struct platform_device *pdev) 0, sspi->tx_irq_name, sspi); if (ret) { dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret); - goto put_spi; + goto disable_clk; } master->dev.of_node = np; @@ -710,7 +711,7 @@ static int synquacer_spi_probe(struct platform_device *pdev) ret = synquacer_spi_enable(master); if (ret) - goto fail_enable; + goto disable_clk; pm_runtime_set_active(sspi->dev); pm_runtime_enable(sspi->dev); @@ -723,7 +724,7 @@ static int synquacer_spi_probe(struct platform_device *pdev) disable_pm: pm_runtime_disable(sspi->dev); -fail_enable: +disable_clk: clk_disable_unprepare(sspi->clk); put_spi: spi_master_put(master); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index ca6886aaa519..a2e5907276e7 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -966,6 +966,7 @@ static int tegra_spi_setup(struct spi_device *spi) ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { + pm_runtime_put_noidle(tspi->dev); dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); if (cdata) tegra_spi_cleanup(spi); @@ -1474,6 +1475,7 @@ static int tegra_spi_resume(struct device *dev) ret = pm_runtime_get_sync(dev); if (ret < 0) { + pm_runtime_put_noidle(dev); dev_err(dev, "pm runtime failed, e = %d\n", ret); return ret; } diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index b59015c7c8a8..cfb7de737937 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -552,6 +552,7 @@ static int tegra_sflash_resume(struct device *dev) ret = pm_runtime_get_sync(dev); if (ret < 0) { + pm_runtime_put_noidle(dev); dev_err(dev, "pm runtime failed, e = %d\n", ret); return ret; } diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index a0810765d4e5..f7c832fd4003 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -751,6 +751,7 @@ static int tegra_slink_setup(struct spi_device *spi) ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { + pm_runtime_put_noidle(tspi->dev); dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); return ret; } @@ -1188,6 +1189,7 @@ static int tegra_slink_resume(struct device *dev) ret = pm_runtime_get_sync(dev); if (ret < 0) { + pm_runtime_put_noidle(dev); dev_err(dev, "pm runtime failed, e = %d\n", ret); return ret; } diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 3c41649698a5..9417385c0921 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -174,6 +174,7 @@ static int ti_qspi_setup(struct spi_device *spi) ret = pm_runtime_get_sync(qspi->dev); if (ret < 0) { + pm_runtime_put_noidle(qspi->dev); dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); return ret; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 45021d271da2..51d7c004fbab 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -374,16 +374,7 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias); } -struct bus_type spi_bus_type = { - .name = "spi", - .dev_groups = spi_dev_groups, - .match = spi_match_device, - .uevent = spi_uevent, -}; -EXPORT_SYMBOL_GPL(spi_bus_type); - - -static int spi_drv_probe(struct device *dev) +static int spi_probe(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); struct spi_device *spi = to_spi_device(dev); @@ -405,31 +396,55 @@ static int spi_drv_probe(struct device *dev) if (ret) return ret; - ret = sdrv->probe(spi); - if (ret) - dev_pm_domain_detach(dev, true); + if (sdrv->probe) { + ret = sdrv->probe(spi); + if (ret) + dev_pm_domain_detach(dev, true); + } return ret; } -static int spi_drv_remove(struct device *dev) +static int spi_remove(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); - int ret; - ret = sdrv->remove(to_spi_device(dev)); + if (sdrv->remove) { + int ret; + + ret = sdrv->remove(to_spi_device(dev)); + if (ret) + dev_warn(dev, + "Failed to unbind driver (%pe), ignoring\n", + ERR_PTR(ret)); + } + dev_pm_domain_detach(dev, true); - return ret; + return 0; } -static void spi_drv_shutdown(struct device *dev) +static void spi_shutdown(struct device *dev) { - const struct spi_driver *sdrv = to_spi_driver(dev->driver); + if (dev->driver) { + const struct spi_driver *sdrv = to_spi_driver(dev->driver); - sdrv->shutdown(to_spi_device(dev)); + if (sdrv->shutdown) + sdrv->shutdown(to_spi_device(dev)); + } } +struct bus_type spi_bus_type = { + .name = "spi", + .dev_groups = spi_dev_groups, + .match = spi_match_device, + .uevent = spi_uevent, + .probe = spi_probe, + .remove = spi_remove, + .shutdown = spi_shutdown, +}; +EXPORT_SYMBOL_GPL(spi_bus_type); + /** * __spi_register_driver - register a SPI driver * @owner: owner module of the driver to register @@ -442,12 +457,6 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv) { sdrv->driver.owner = owner; sdrv->driver.bus = &spi_bus_type; - if (sdrv->probe) - sdrv->driver.probe = spi_drv_probe; - if (sdrv->remove) - sdrv->driver.remove = spi_drv_remove; - if (sdrv->shutdown) - sdrv->driver.shutdown = spi_drv_shutdown; return driver_register(&sdrv->driver); } EXPORT_SYMBOL_GPL(__spi_register_driver); @@ -3238,9 +3247,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr, } /** - * spi_split_tranfers_maxsize - split spi transfers into multiple transfers - * when an individual transfer exceeds a - * certain size + * spi_split_transfers_maxsize - split spi transfers into multiple transfers + * when an individual transfer exceeds a + * certain size * @ctlr: the @spi_controller for this transfer * @msg: the @spi_message to transform * @maxsize: the maximum when to apply this |