summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-pl022.c
diff options
context:
space:
mode:
authorChris Blair <chris.blair@stericsson.com>2011-11-04 08:43:41 +0100
committerLinus Walleij <linus.walleij@linaro.org>2011-12-01 17:16:08 +0100
commitd4b6af2e0e29278f2353c7c8721ddf2f2446414f (patch)
tree4b900739272b0072c0a9057760de0a928c6c8962 /drivers/spi/spi-pl022.c
parentspi/pl022: skip default configuration before suspending (diff)
downloadlinux-d4b6af2e0e29278f2353c7c8721ddf2f2446414f.tar.xz
linux-d4b6af2e0e29278f2353c7c8721ddf2f2446414f.zip
spi/pl022: move device disable to workqueue thread
Moves the disabling of the device and clocks to the same thread in which the device and clocks are enabled. This avoids SMP issues where the device can be enabled for a transfer by one thread and then disabled by the completion of the previous transfer in another thread. Reviewed-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Chris Blair <chris.blair@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/spi/spi-pl022.c')
-rw-r--r--drivers/spi/spi-pl022.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index b4038f97f6b0..d165c0bfcab5 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -512,8 +512,6 @@ static void giveback(struct pl022 *pl022)
msg->state = NULL;
if (msg->complete)
msg->complete(msg->context);
- /* This message is completed, so let's turn off the clocks & power */
- pm_runtime_put(&pl022->adev->dev);
}
/**
@@ -1509,14 +1507,18 @@ static void pump_messages(struct work_struct *work)
struct pl022 *pl022 =
container_of(work, struct pl022, pump_messages);
unsigned long flags;
+ bool was_busy = false;
/* Lock queue and check for queue work */
spin_lock_irqsave(&pl022->queue_lock, flags);
if (list_empty(&pl022->queue) || !pl022->running) {
+ if (pl022->busy)
+ pm_runtime_put(&pl022->adev->dev);
pl022->busy = false;
spin_unlock_irqrestore(&pl022->queue_lock, flags);
return;
}
+
/* Make sure we are not already running a message */
if (pl022->cur_msg) {
spin_unlock_irqrestore(&pl022->queue_lock, flags);
@@ -1527,7 +1529,10 @@ static void pump_messages(struct work_struct *work)
list_entry(pl022->queue.next, struct spi_message, queue);
list_del_init(&pl022->cur_msg->queue);
- pl022->busy = true;
+ if (pl022->busy)
+ was_busy = true;
+ else
+ pl022->busy = true;
spin_unlock_irqrestore(&pl022->queue_lock, flags);
/* Initial message state */
@@ -1537,12 +1542,14 @@ static void pump_messages(struct work_struct *work)
/* Setup the SPI using the per chip configuration */
pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
- /*
- * We enable the core voltage and clocks here, then the clocks
- * and core will be disabled when giveback() is called in each method
- * (poll/interrupt/DMA)
- */
- pm_runtime_get_sync(&pl022->adev->dev);
+ if (!was_busy)
+ /*
+ * We enable the core voltage and clocks here, then the clocks
+ * and core will be disabled when this workqueue is run again
+ * and there is no more work to be done.
+ */
+ pm_runtime_get_sync(&pl022->adev->dev);
+
restore_state(pl022);
flush(pl022);