changed Makefile and profiles, added patches for kernel 2.6.24
[openwrt.git] / target / linux / s3c24xx / patches-2.6.24 / 1182-ASoC-Don-t-block-system-resume.patch
diff --git a/target/linux/s3c24xx/patches-2.6.24/1182-ASoC-Don-t-block-system-resume.patch b/target/linux/s3c24xx/patches-2.6.24/1182-ASoC-Don-t-block-system-resume.patch
new file mode 100644 (file)
index 0000000..347dbfb
--- /dev/null
@@ -0,0 +1,125 @@
+From 2219855aa7835e082ec134fafd9ddba84589d345 Mon Sep 17 00:00:00 2001
+From: Andy Green <andy@openmoko.com>
+Date: Wed, 2 Jul 2008 22:39:33 +0100
+Subject: [PATCH] ASoC: Don't block system resume
+
+On OpenMoko soc-audio resume is taking 700ms of the whole resume time of
+1.3s, dominated by writes to the codec over I2C.  This patch shunts the
+resume guts into a workqueue which then is done asynchronously.
+
+The "card" is locked using the ALSA power state APIs as suggested by
+Mark Brown.
+
+[Added fix for race with resume to suspend and fixed a couple of nits
+from checkpatch -- broonie.]
+
+Signed-off-by: Andy Green <andy@openmoko.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+---
+ include/sound/soc.h  |    1 +
+ sound/soc/soc-core.c |   52 ++++++++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 47 insertions(+), 6 deletions(-)
+
+diff --git a/include/sound/soc.h b/include/sound/soc.h
+index aedb348..2d6c0eb 100644
+--- a/include/sound/soc.h
++++ b/include/sound/soc.h
+@@ -442,6 +442,7 @@ struct snd_soc_device {
+       struct snd_soc_codec *codec;
+       struct snd_soc_codec_device *codec_dev;
+       struct delayed_work delayed_work;
++      struct work_struct deferred_resume_work;
+       void *codec_data;
+ };
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 9e20333..e96930e 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -632,6 +632,16 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
++      /* Due to the resume being scheduled into a workqueue we could
++      * suspend before that's finished - wait for it to complete.
++       */
++      snd_power_lock(codec->card);
++      snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
++      snd_power_unlock(codec->card);
++
++      /* we're going to block userspace touching us until resume completes */
++      snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
++
+       /* mute any active DAC's */
+       for(i = 0; i < machine->num_links; i++) {
+               struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
+@@ -684,16 +694,27 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
+       return 0;
+ }
+-/* powers up audio subsystem after a suspend */
+-static int soc_resume(struct platform_device *pdev)
++/* deferred resume work, so resume can complete before we finished
++ * setting our codec back up, which can be very slow on I2C
++ */
++static void soc_resume_deferred(struct work_struct *work)
+ {
+-      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+-      struct snd_soc_machine *machine = socdev->machine;
+-      struct snd_soc_platform *platform = socdev->platform;
+-      struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
++      struct snd_soc_device *socdev = container_of(work,
++                                                   struct snd_soc_device,
++                                                   deferred_resume_work);
++      struct snd_soc_machine *machine = socdev->machine;
++      struct snd_soc_platform *platform = socdev->platform;
++      struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+       struct snd_soc_codec *codec = socdev->codec;
++      struct platform_device *pdev = to_platform_device(socdev->dev);
+       int i;
++      /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
++       * so userspace apps are blocked from touching us
++       */
++
++      dev_info(socdev->dev, "starting resume work\n");
++
+       if (machine->resume_pre)
+               machine->resume_pre(pdev);
+@@ -735,6 +756,22 @@ static int soc_resume(struct platform_device *pdev)
+       if (machine->resume_post)
+               machine->resume_post(pdev);
++      dev_info(socdev->dev, "resume work completed\n");
++
++      /* userspace can access us now we are back as we were before */
++      snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
++}
++
++/* powers up audio subsystem after a suspend */
++static int soc_resume(struct platform_device *pdev)
++{
++      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++
++      dev_info(socdev->dev, "scheduling resume work\n");
++
++      if (!schedule_work(&socdev->deferred_resume_work))
++              dev_err(socdev->dev, "work item may be lost\n");
++
+       return 0;
+ }
+@@ -781,6 +818,9 @@ static int soc_probe(struct platform_device *pdev)
+       /* DAPM stream work */
+       INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work);
++      /* deferred resume work */
++      INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred);
++
+       return 0;
+ platform_err:
+-- 
+1.5.6.5
+