[ARM] tegra_i2s/spdif_audio: move allow_suspend to a work queue
authorIliyan Malchev <malchev@google.com>
Fri, 5 Nov 2010 20:03:35 +0000 (13:03 -0700)
committerIliyan Malchev <malchev@google.com>
Fri, 5 Nov 2010 20:34:43 +0000 (13:34 -0700)
Since pm_qos_update_request() may block, we need to make sure that
allow_suspend is always called in process context.

Signed-off-by: Iliyan Malchev <malchev@google.com>
arch/arm/mach-tegra/tegra_i2s_audio.c
arch/arm/mach-tegra/tegra_spdif_audio.c

index e5c0436d5f1bd7d046f5a4d1ebefbae8e174f48a..d62bf234259190f87040464c416df0daedb06422 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/delay.h>
 #include <linux/tegra_audio.h>
 #include <linux/pm.h>
+#include <linux/workqueue.h>
+
 #include <mach/dma.h>
 #include <mach/iomap.h>
 #include <mach/i2s.h>
@@ -90,6 +92,7 @@ struct audio_stream {
        struct tegra_dma_req dma_req;
 
        struct pm_qos_request_list pm_qos;
+       struct work_struct allow_suspend_work;
 };
 
 struct i2s_pio_stats {
@@ -218,15 +221,24 @@ static inline struct audio_driver_state *ads_from_in(
 static inline void prevent_suspend(struct audio_stream *as)
 {
        pr_debug("%s\n", __func__);
+       cancel_work_sync(&as->allow_suspend_work);
        pm_qos_update_request(&as->pm_qos, 0);
 }
 
-static inline void allow_suspend(struct audio_stream *as)
+static void allow_suspend_worker(struct work_struct *w)
 {
+       struct audio_stream *as = container_of(w,
+                       struct audio_stream, allow_suspend_work);
+
        pr_debug("%s\n", __func__);
        pm_qos_update_request(&as->pm_qos, PM_QOS_DEFAULT_VALUE);
 }
 
+static inline void allow_suspend(struct audio_stream *as)
+{
+       schedule_work(&as->allow_suspend_work);
+}
+
 #define I2S_I2S_FIFO_TX_BUSY   I2S_I2S_STATUS_FIFO1_BSY
 #define I2S_I2S_FIFO_TX_QS     I2S_I2S_STATUS_QS_FIFO1
 #define I2S_I2S_FIFO_TX_ERR    I2S_I2S_STATUS_FIFO1_ERR
@@ -2451,6 +2463,7 @@ static int tegra_audio_probe(struct platform_device *pdev)
                if (rc < 0)
                        return rc;
 
+               INIT_WORK(&state->out.allow_suspend_work, allow_suspend_worker);
                pm_qos_add_request(&state->out.pm_qos, PM_QOS_CPU_DMA_LATENCY,
                                PM_QOS_DEFAULT_VALUE);
 
@@ -2488,6 +2501,7 @@ static int tegra_audio_probe(struct platform_device *pdev)
                if (rc < 0)
                        return rc;
 
+               INIT_WORK(&state->in.allow_suspend_work, allow_suspend_worker);
                pm_qos_add_request(&state->in.pm_qos, PM_QOS_CPU_DMA_LATENCY,
                                        PM_QOS_DEFAULT_VALUE);
 
index 3764edfdf86935d5f90a765cf21b5125bbf90644..1c22e4537876b0b751e26a672d44783b049d77f9 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/pm_qos_params.h>
 #include <linux/delay.h>
 #include <linux/tegra_audio.h>
+#include <linux/workqueue.h>
 
 #include <mach/dma.h>
 #include <mach/iomap.h>
@@ -88,6 +89,7 @@ struct audio_stream {
        struct tegra_dma_req dma_req;
 
        struct pm_qos_request_list pm_qos;
+       struct work_struct allow_suspend_work;
 };
 
 struct spdif_pio_stats {
@@ -162,15 +164,24 @@ static inline struct audio_driver_state *ads_from_out(
 static inline void prevent_suspend(struct audio_stream *as)
 {
        pr_debug("%s\n", __func__);
+       cancel_work_sync(&as->allow_suspend_work);
        pm_qos_update_request(&as->pm_qos, 0);
 }
 
-static inline void allow_suspend(struct audio_stream *as)
+static void allow_suspend_worker(struct work_struct *w)
 {
+       struct audio_stream *as = container_of(w,
+                       struct audio_stream, allow_suspend_work);
+
        pr_debug("%s\n", __func__);
        pm_qos_update_request(&as->pm_qos, PM_QOS_DEFAULT_VALUE);
 }
 
+static inline void allow_suspend(struct audio_stream *as)
+{
+       schedule_work(&as->allow_suspend_work);
+}
+
 #define I2S_I2S_FIFO_TX_BUSY   I2S_I2S_STATUS_FIFO1_BSY
 #define I2S_I2S_FIFO_TX_QS     I2S_I2S_STATUS_QS_FIFO1
 #define I2S_I2S_FIFO_TX_ERR    I2S_I2S_STATUS_FIFO1_ERR
@@ -1337,6 +1348,7 @@ static int tegra_spdif_probe(struct platform_device *pdev)
        if (rc < 0)
                return rc;
 
+       INIT_WORK(&state->out.allow_suspend_work, allow_suspend_worker);
        pm_qos_add_request(&state->out.pm_qos, PM_QOS_CPU_DMA_LATENCY,
                                PM_QOS_DEFAULT_VALUE);