summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/atmel-quadspi.c2
-rw-r--r--drivers/spi/spi-amd.c5
-rw-r--r--drivers/spi/spi-atmel.c6
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c4
-rw-r--r--drivers/spi/spi-dw-bt1.c2
-rw-r--r--drivers/spi/spi-img-spfi.c4
-rw-r--r--drivers/spi/spi-imx.c33
-rw-r--r--drivers/spi/spi-mem.c3
-rw-r--r--drivers/spi/spi-mt7621.c2
-rw-r--r--drivers/spi/spi-mtk-nor.c16
-rw-r--r--drivers/spi/spi-mxs.c1
-rw-r--r--drivers/spi/spi-pic32.c1
-rw-r--r--drivers/spi/spi-rockchip.c4
-rw-r--r--drivers/spi/spi-sprd.c1
-rw-r--r--drivers/spi/spi-st-ssc4.c5
-rw-r--r--drivers/spi/spi-stm32-qspi.c8
-rw-r--r--drivers/spi/spi-stm32.c1
-rw-r--r--drivers/spi/spi-sun6i.c199
-rw-r--r--drivers/spi/spi-synquacer.c15
-rw-r--r--drivers/spi/spi-tegra114.c2
-rw-r--r--drivers/spi/spi-tegra20-sflash.c1
-rw-r--r--drivers/spi/spi-tegra20-slink.c2
-rw-r--r--drivers/spi/spi-ti-qspi.c1
-rw-r--r--drivers/spi/spi.c67
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