summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-tegra.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-tegra.c')
-rw-r--r--drivers/spi/spi-tegra.c182
1 files changed, 102 insertions, 80 deletions
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index 05c2d2c2607b..d4b9c3344eee 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -1185,6 +1185,87 @@ static irqreturn_t spi_tegra_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
+static void spi_tegra_deinit_dma_param(struct spi_tegra_data *tspi,
+ bool dma_to_memory)
+{
+ struct tegra_dma_channel *tdc;
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+
+ if (dma_to_memory) {
+ dma_buf = tspi->rx_buf;
+ tdc = tspi->rx_dma;
+ dma_phys = tspi->rx_buf_phys;
+ tspi->rx_dma = NULL;
+ tspi->rx_buf = NULL;
+ } else {
+ dma_buf = tspi->tx_buf;
+ tdc = tspi->tx_dma;
+ dma_phys = tspi->tx_buf_phys;
+ tspi->tx_buf = NULL;
+ tspi->tx_dma = NULL;
+ }
+
+ dma_free_coherent(&tspi->pdev->dev, tspi->dma_buf_size,
+ dma_buf, dma_phys);
+ tegra_dma_free_channel(tdc);
+}
+
+static int __init spi_tegra_init_dma_param(struct spi_tegra_data *tspi,
+ bool dma_to_memory)
+{
+ struct tegra_dma_req *dma_req;
+ struct tegra_dma_channel *tdc;
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+
+ tdc = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT, "spi_%s_%d",
+ (dma_to_memory) ? "rx" : "tx", tspi->pdev->id);
+ if (!tdc) {
+ dev_err(&tspi->pdev->dev, "can not allocate rx dma channel\n");
+ return -ENODEV;
+ }
+
+ dma_buf = dma_alloc_coherent(&tspi->pdev->dev, tspi->dma_buf_size,
+ &dma_phys, GFP_KERNEL);
+ if (!dma_buf) {
+ dev_err(&tspi->pdev->dev, "can not allocate rx bounce buffer");
+ tegra_dma_free_channel(tdc);
+ return -ENOMEM;
+ }
+
+ dma_req = (dma_to_memory) ? &tspi->rx_dma_req : &tspi->tx_dma_req;
+ memset(dma_req, 0, sizeof(*dma_req));
+
+ dma_req->req_sel = spi_tegra_req_sels[tspi->pdev->id];
+ dma_req->dev = tspi;
+ dma_req->dest_bus_width = 32;
+ dma_req->source_bus_width = 32;
+ dma_req->to_memory = (dma_to_memory) ? 1 : 0;
+ dma_req->virt_addr = dma_buf;
+ dma_req->dest_wrap = 0;
+ dma_req->source_wrap = 0;
+
+ if (dma_to_memory) {
+ dma_req->complete = tegra_spi_rx_dma_complete;
+ dma_req->dest_addr = dma_phys;
+ dma_req->source_addr = tspi->phys + SLINK_RX_FIFO;
+ dma_req->source_wrap = 4;
+ tspi->rx_buf_phys = dma_phys;
+ tspi->rx_buf = dma_buf;
+ tspi->rx_dma = tdc;
+ } else {
+ dma_req->complete = tegra_spi_tx_dma_complete;
+ dma_req->dest_addr = tspi->phys + SLINK_TX_FIFO;
+ dma_req->source_addr = dma_phys;
+ dma_req->dest_wrap = 4;
+ tspi->tx_buf = dma_buf;
+ tspi->tx_buf_phys = dma_phys;
+ tspi->tx_dma = tdc;
+ }
+ return 0;
+}
+
static int __init spi_tegra_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -1306,64 +1387,18 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
init_completion(&tspi->tx_dma_complete);
init_completion(&tspi->rx_dma_complete);
-
- tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT,
- "spi_rx_%d", pdev->id);
- if (!tspi->rx_dma) {
- dev_err(&pdev->dev, "can not allocate rx dma channel\n");
- ret = -ENODEV;
+ ret = spi_tegra_init_dma_param(tspi, true);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error in rx dma init\n");
goto exit_free_master;
}
- tspi->rx_buf = dma_alloc_coherent(&pdev->dev, tspi->dma_buf_size,
- &tspi->rx_buf_phys, GFP_KERNEL);
- if (!tspi->rx_buf) {
- dev_err(&pdev->dev, "can not allocate rx bounce buffer\n");
- ret = -ENOMEM;
- goto fail_rx_buf_alloc;
- }
-
- memset(&tspi->rx_dma_req, 0, sizeof(struct tegra_dma_req));
- tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete;
- tspi->rx_dma_req.to_memory = 1;
- tspi->rx_dma_req.dest_addr = tspi->rx_buf_phys;
- tspi->rx_dma_req.virt_addr = tspi->rx_buf;
- tspi->rx_dma_req.dest_bus_width = 32;
- tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO;
- tspi->rx_dma_req.source_bus_width = 32;
- tspi->rx_dma_req.source_wrap = 4;
- tspi->rx_dma_req.dest_wrap = 0;
- tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
- tspi->rx_dma_req.dev = tspi;
-
- tspi->tx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT,
- "spi_tx_%d", pdev->id);
- if (!tspi->tx_dma) {
- dev_err(&pdev->dev, "can not allocate tx dma channel\n");
- ret = -ENODEV;
- goto fail_tx_dma_alloc;
- }
-
- tspi->tx_buf = dma_alloc_coherent(&pdev->dev, tspi->dma_buf_size,
- &tspi->tx_buf_phys, GFP_KERNEL);
- if (!tspi->tx_buf) {
- dev_err(&pdev->dev, "can not allocate tx bounce buffer\n");
- ret = -ENOMEM;
- goto fail_tx_buf_alloc;
+ ret = spi_tegra_init_dma_param(tspi, false);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error in tx dma init\n");
+ goto exit_rx_dma_free;
}
- memset(&tspi->tx_dma_req, 0, sizeof(struct tegra_dma_req));
- tspi->tx_dma_req.complete = tegra_spi_tx_dma_complete;
- tspi->tx_dma_req.to_memory = 0;
- tspi->tx_dma_req.dest_addr = tspi->phys + SLINK_TX_FIFO;
- tspi->tx_dma_req.virt_addr = tspi->tx_buf;
- tspi->tx_dma_req.dest_bus_width = 32;
- tspi->tx_dma_req.dest_wrap = 4;
- tspi->tx_dma_req.source_wrap = 0;
- tspi->tx_dma_req.source_addr = tspi->tx_buf_phys;
- tspi->tx_dma_req.source_bus_width = 32;
- tspi->tx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
- tspi->tx_dma_req.dev = tspi;
tspi->max_buf_size = tspi->dma_buf_size;
tspi->def_command_reg = SLINK_CS_SW | SLINK_M_S;
tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN;
@@ -1374,7 +1409,7 @@ skip_dma_alloc:
ret = tegra_spi_runtime_resume(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "runtime resume failed %d", ret);
- goto err_pm_disable;
+ goto exit_pm_disable;
}
}
@@ -1386,7 +1421,7 @@ skip_dma_alloc:
ret = spi_register_master(master);
if (ret < 0) {
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
- goto fail_master_register;
+ goto exit_pm_suspend;
}
/* create the workqueue for the kbc path */
@@ -1395,39 +1430,30 @@ skip_dma_alloc:
if (!tspi->spi_workqueue) {
dev_err(&pdev->dev, "Failed to create work queue\n");
ret = -ENODEV;
- goto fail_workqueue;
+ goto exit_master_unregister;
}
INIT_WORK(&tspi->spi_transfer_work, tegra_spi_transfer_work);
return ret;
-fail_workqueue:
+exit_master_unregister:
spi_unregister_master(master);
-fail_master_register:
if (tspi->is_clkon_always)
pm_runtime_put_sync(&pdev->dev);
+exit_pm_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
tegra_spi_runtime_idle(&pdev->dev);
-err_pm_disable:
+exit_pm_disable:
pm_runtime_disable(&pdev->dev);
- if (tspi->tx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->tx_buf, tspi->tx_buf_phys);
-fail_tx_buf_alloc:
- if (tspi->tx_dma)
- tegra_dma_free_channel(tspi->tx_dma);
-fail_tx_dma_alloc:
- if (tspi->rx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->rx_buf, tspi->rx_buf_phys);
-fail_rx_buf_alloc:
- if (tspi->rx_dma)
- tegra_dma_free_channel(tspi->rx_dma);
+ spi_tegra_deinit_dma_param(tspi, false);
+
+exit_rx_dma_free:
+ spi_tegra_deinit_dma_param(tspi, true);
exit_free_master:
spi_master_put(master);
@@ -1443,16 +1469,12 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
tspi = spi_master_get_devdata(master);
spi_unregister_master(master);
- if (tspi->tx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->tx_buf, tspi->tx_buf_phys);
+
if (tspi->tx_dma)
- tegra_dma_free_channel(tspi->tx_dma);
- if (tspi->rx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->rx_buf, tspi->rx_buf_phys);
+ spi_tegra_deinit_dma_param(tspi, false);
+
if (tspi->rx_dma)
- tegra_dma_free_channel(tspi->rx_dma);
+ spi_tegra_deinit_dma_param(tspi, true);
/* Disable clock if it is always enabled */
if (tspi->is_clkon_always)