From 86d007b0f88e0bcc859923cb3d13dc310d5bf057 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Fri, 5 Nov 2010 13:03:35 -0700 Subject: [PATCH] [ARM] tegra_i2s/spdif_audio: move allow_suspend to a work queue 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 --- arch/arm/mach-tegra/tegra_i2s_audio.c | 16 +++++++++++++++- arch/arm/mach-tegra/tegra_spdif_audio.c | 14 +++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-tegra/tegra_i2s_audio.c b/arch/arm/mach-tegra/tegra_i2s_audio.c index e5c0436d5f1b..d62bf2342591 100644 --- a/arch/arm/mach-tegra/tegra_i2s_audio.c +++ b/arch/arm/mach-tegra/tegra_i2s_audio.c @@ -44,6 +44,8 @@ #include #include #include +#include + #include #include #include @@ -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); diff --git a/arch/arm/mach-tegra/tegra_spdif_audio.c b/arch/arm/mach-tegra/tegra_spdif_audio.c index 3764edfdf869..1c22e4537876 100644 --- a/arch/arm/mach-tegra/tegra_spdif_audio.c +++ b/arch/arm/mach-tegra/tegra_spdif_audio.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -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); -- 2.34.1