diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/atmel-quadspi.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-amd.c | 5 | ||||
-rw-r--r-- | drivers/spi/spi-atmel.c | 6 | ||||
-rw-r--r-- | drivers/spi/spi-bcm63xx-hsspi.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-dw-bt1.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-img-spfi.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-imx.c | 33 | ||||
-rw-r--r-- | drivers/spi/spi-mem.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-mt7621.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-mtk-nor.c | 16 | ||||
-rw-r--r-- | drivers/spi/spi-mxs.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-pic32.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-rockchip.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-sprd.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-st-ssc4.c | 5 | ||||
-rw-r--r-- | drivers/spi/spi-stm32-qspi.c | 8 | ||||
-rw-r--r-- | drivers/spi/spi-stm32.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-sun6i.c | 199 | ||||
-rw-r--r-- | drivers/spi/spi-synquacer.c | 15 | ||||
-rw-r--r-- | drivers/spi/spi-tegra114.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-tegra20-sflash.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-tegra20-slink.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-ti-qspi.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi.c | 67 |
24 files changed, 283 insertions, 102 deletions
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 8c009c175f2c..b44521d4a245 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -594,7 +594,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) 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) { 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-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-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index f382dfad7842..da4f4d82617c 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-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..2cdae7994e2a 100644 --- a/drivers/spi/spi-mt7621.c +++ b/drivers/spi/spi-mt7621.c @@ -353,6 +353,7 @@ static int mt7621_spi_probe(struct platform_device *pdev) master = spi_alloc_master(&pdev->dev, sizeof(*rs)); if (!master) { dev_info(&pdev->dev, "master allocation failed\n"); + clk_disable_unprepare(clk); return -ENOMEM; } @@ -377,6 +378,7 @@ 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; } diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index b97f26a60cbe..bf2d0f9cdd19 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,6 +771,10 @@ 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); @@ -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-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-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-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-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 fc9a59788d2e..cd3c395b4e90 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 |