Commit de082d86 authored by Lanqing Liu's avatar Lanqing Liu Committed by Mark Brown

spi: sprd: Add the SPI irq function for the SPI DMA mode

The SPI irq event will use to complete the SPI work in the SPI DMA mode,
so this patch is a preparation for the following DMA mode support.

Moreover the SPI interrupt can be fired when removing the SPI controller,
so we should make sure the SPI controller has stopped the queue in
remove function before freeing the SPI irq.
Signed-off-by: default avatarLanqing Liu <lanqing.liu@unisoc.com>
Signed-off-by: default avatarBaolin Wang <baolin.wang@linaro.org>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 97a6a2dd
...@@ -133,6 +133,7 @@ struct sprd_spi { ...@@ -133,6 +133,7 @@ struct sprd_spi {
void __iomem *base; void __iomem *base;
struct device *dev; struct device *dev;
struct clk *clk; struct clk *clk;
int irq;
u32 src_clk; u32 src_clk;
u32 hw_mode; u32 hw_mode;
u32 trans_len; u32 trans_len;
...@@ -141,6 +142,7 @@ struct sprd_spi { ...@@ -141,6 +142,7 @@ struct sprd_spi {
u32 hw_speed_hz; u32 hw_speed_hz;
u32 len; u32 len;
int status; int status;
struct completion xfer_completion;
const void *tx_buf; const void *tx_buf;
void *rx_buf; void *rx_buf;
int (*read_bufs)(struct sprd_spi *ss, u32 len); int (*read_bufs)(struct sprd_spi *ss, u32 len);
...@@ -573,6 +575,48 @@ static int sprd_spi_transfer_one(struct spi_controller *sctlr, ...@@ -573,6 +575,48 @@ static int sprd_spi_transfer_one(struct spi_controller *sctlr,
return ret; return ret;
} }
static irqreturn_t sprd_spi_handle_irq(int irq, void *data)
{
struct sprd_spi *ss = (struct sprd_spi *)data;
u32 val = readl_relaxed(ss->base + SPRD_SPI_INT_MASK_STS);
if (val & SPRD_SPI_MASK_TX_END) {
writel_relaxed(SPRD_SPI_TX_END_CLR, ss->base + SPRD_SPI_INT_CLR);
if (!(ss->trans_mode & SPRD_SPI_RX_MODE))
complete(&ss->xfer_completion);
return IRQ_HANDLED;
}
if (val & SPRD_SPI_MASK_RX_END) {
writel_relaxed(SPRD_SPI_RX_END_CLR, ss->base + SPRD_SPI_INT_CLR);
complete(&ss->xfer_completion);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int sprd_spi_irq_init(struct platform_device *pdev, struct sprd_spi *ss)
{
int ret;
ss->irq = platform_get_irq(pdev, 0);
if (ss->irq < 0) {
dev_err(&pdev->dev, "failed to get irq resource\n");
return ss->irq;
}
ret = devm_request_irq(&pdev->dev, ss->irq, sprd_spi_handle_irq,
0, pdev->name, ss);
if (ret)
dev_err(&pdev->dev, "failed to request spi irq %d, ret = %d\n",
ss->irq, ret);
return ret;
}
static int sprd_spi_clk_init(struct platform_device *pdev, struct sprd_spi *ss) static int sprd_spi_clk_init(struct platform_device *pdev, struct sprd_spi *ss)
{ {
struct clk *clk_spi, *clk_parent; struct clk *clk_spi, *clk_parent;
...@@ -633,11 +677,16 @@ static int sprd_spi_probe(struct platform_device *pdev) ...@@ -633,11 +677,16 @@ static int sprd_spi_probe(struct platform_device *pdev)
sctlr->max_speed_hz = min_t(u32, ss->src_clk >> 1, sctlr->max_speed_hz = min_t(u32, ss->src_clk >> 1,
SPRD_SPI_MAX_SPEED_HZ); SPRD_SPI_MAX_SPEED_HZ);
init_completion(&ss->xfer_completion);
platform_set_drvdata(pdev, sctlr); platform_set_drvdata(pdev, sctlr);
ret = sprd_spi_clk_init(pdev, ss); ret = sprd_spi_clk_init(pdev, ss);
if (ret) if (ret)
goto free_controller; goto free_controller;
ret = sprd_spi_irq_init(pdev, ss);
if (ret)
goto free_controller;
ret = clk_prepare_enable(ss->clk); ret = clk_prepare_enable(ss->clk);
if (ret) if (ret)
goto free_controller; goto free_controller;
...@@ -688,6 +737,8 @@ static int sprd_spi_remove(struct platform_device *pdev) ...@@ -688,6 +737,8 @@ static int sprd_spi_remove(struct platform_device *pdev)
return ret; return ret;
} }
spi_controller_suspend(sctlr);
clk_disable_unprepare(ss->clk); clk_disable_unprepare(ss->clk);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment