summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-tegra.c
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2011-09-13 18:27:55 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2012-03-23 16:10:07 -0700
commit13da6e9163a8489efcd7b83e767f4bb289a13997 (patch)
tree4f8e6882afa4e1d22ab52fd857e4bca8db7c6c73 /drivers/spi/spi-tegra.c
parent8de9bfbe536d931ba94b52c9a06aa9e2acbc8129 (diff)
spi: tegra: Handles suspend when spi transfer is in progress
Avoiding the suspend of the system if the spi transfer is in progress for current transfer queue. bug 864987 Reviewed-on: http://git-master/r/56599 (cherry picked from commit 0ba8ed371f2937a095752a0edbc15ed75664644a) Change-Id: Ife7ae8a7d66a66d047ee2c8829d16017571b4d58 Reviewed-on: http://git-master/r/57001 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> Tested-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-by: Bitan Biswas <bbiswas@nvidia.com> Rebase-Id: Rc66d6c7ae51ea6709d5e47331fef30c87029b343
Diffstat (limited to 'drivers/spi/spi-tegra.c')
-rw-r--r--drivers/spi/spi-tegra.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index 223680298d47..28e011d723a4 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -220,6 +220,7 @@ struct spi_tegra_data {
struct completion rx_dma_complete;
struct completion tx_dma_complete;
+ bool is_transfer_in_progress;
u32 rx_complete;
u32 tx_complete;
@@ -678,6 +679,7 @@ static void spi_tegra_start_transfer(struct spi_device *spi,
command2 = tspi->def_command2_reg;
if (is_first_of_msg) {
+ tspi->is_transfer_in_progress = true;
if (!tspi->is_clkon_always) {
if (!tspi->clk_state) {
clk_enable(tspi->clk);
@@ -900,6 +902,7 @@ static void spi_tegra_curr_transfer_complete(struct spi_tegra_data *tspi,
spi = m->state;
m->actual_length += cur_xfer_size;
+
if (!list_is_last(&tspi->cur->transfer_list, &m->transfers)) {
tspi->cur = list_first_entry(&tspi->cur->transfer_list,
struct spi_transfer, transfer_list);
@@ -908,6 +911,8 @@ static void spi_tegra_curr_transfer_complete(struct spi_tegra_data *tspi,
list_del(&m->queue);
m->complete(m->context);
if (!list_empty(&tspi->queue)) {
+ if (tspi->is_suspended)
+ goto stop_transfer;
m = list_first_entry(&tspi->queue, struct spi_message,
queue);
spi = m->state;
@@ -926,8 +931,15 @@ static void spi_tegra_curr_transfer_complete(struct spi_tegra_data *tspi,
tspi->clk_state = 0;
}
}
+ tspi->is_transfer_in_progress = false;
}
}
+ return;
+stop_transfer:
+ spi_tegra_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
+ spi_tegra_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
+ tspi->is_transfer_in_progress = false;
+ return;
}
static void tegra_spi_tx_dma_complete(struct tegra_dma_req *req)
@@ -1126,6 +1138,7 @@ static int __devinit spi_tegra_probe(struct platform_device *pdev)
tspi = spi_master_get_devdata(master);
tspi->master = master;
tspi->pdev = pdev;
+ tspi->is_transfer_in_progress = false;
spin_lock_init(&tspi->lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1366,9 +1379,12 @@ static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state)
master = dev_get_drvdata(&pdev->dev);
tspi = spi_master_get_devdata(master);
spin_lock_irqsave(&tspi->lock, flags);
- tspi->is_suspended = true;
- WARN_ON(!list_empty(&tspi->queue));
+ /* Wait for all transfer completes */
+ if (!list_empty(&tspi->queue))
+ dev_warn(&pdev->dev, "The transfer list is not empty "
+ "Waiting for time %d ms to complete transfer\n",
+ limit * 20);
while (!list_empty(&tspi->queue) && limit--) {
spin_unlock_irqrestore(&tspi->lock, flags);
@@ -1376,6 +1392,28 @@ static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state)
spin_lock_irqsave(&tspi->lock, flags);
}
+ /* Wait for current transfer completes only */
+ tspi->is_suspended = true;
+ if (!list_empty(&tspi->queue)) {
+ limit = 50;
+ dev_err(&pdev->dev, "All transfer has not completed, "
+ "Waiting for %d ms current transfer to complete\n",
+ limit * 20);
+ while (tspi->is_transfer_in_progress && limit--) {
+ spin_unlock_irqrestore(&tspi->lock, flags);
+ msleep(20);
+ spin_lock_irqsave(&tspi->lock, flags);
+ }
+ }
+
+ if (tspi->is_transfer_in_progress) {
+ dev_err(&pdev->dev, "Spi transfer is in progress "
+ "Avoiding suspend\n");
+ tspi->is_suspended = false;
+ spi_unlock_irqrestore(&tspi->lock, flags);
+ return -EBUSY;
+ }
+
spin_unlock_irqrestore(&tspi->lock, flags);
if (tspi->is_clkon_always) {
clk_disable(tspi->clk);
@@ -1389,6 +1427,8 @@ static int spi_tegra_resume(struct platform_device *pdev)
struct spi_master *master;
struct spi_tegra_data *tspi;
unsigned long flags;
+ struct spi_message *m;
+ struct spi_device *spi;
master = dev_get_drvdata(&pdev->dev);
tspi = spi_master_get_devdata(master);
@@ -1404,6 +1444,11 @@ static int spi_tegra_resume(struct platform_device *pdev)
tspi->cur_speed = 0;
tspi->is_suspended = false;
+ if (!list_empty(&tspi->queue)) {
+ m = list_first_entry(&tspi->queue, struct spi_message, queue);
+ spi = m->state;
+ spi_tegra_start_message(spi, m);
+ }
spin_unlock_irqrestore(&tspi->lock, flags);
return 0;
}