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
1 From 2219855aa7835e082ec134fafd9ddba84589d345 Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Wed, 2 Jul 2008 22:39:33 +0100
4 Subject: [PATCH] ASoC: Don't block system resume
5
6 On OpenMoko soc-audio resume is taking 700ms of the whole resume time of
7 1.3s, dominated by writes to the codec over I2C.  This patch shunts the
8 resume guts into a workqueue which then is done asynchronously.
9
10 The "card" is locked using the ALSA power state APIs as suggested by
11 Mark Brown.
12
13 [Added fix for race with resume to suspend and fixed a couple of nits
14 from checkpatch -- broonie.]
15
16 Signed-off-by: Andy Green <andy@openmoko.com>
17 Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
18 ---
19  include/sound/soc.h  |    1 +
20  sound/soc/soc-core.c |   52 ++++++++++++++++++++++++++++++++++++++++++++-----
21  2 files changed, 47 insertions(+), 6 deletions(-)
22
23 diff --git a/include/sound/soc.h b/include/sound/soc.h
24 index aedb348..2d6c0eb 100644
25 --- a/include/sound/soc.h
26 +++ b/include/sound/soc.h
27 @@ -442,6 +442,7 @@ struct snd_soc_device {
28         struct snd_soc_codec *codec;
29         struct snd_soc_codec_device *codec_dev;
30         struct delayed_work delayed_work;
31 +       struct work_struct deferred_resume_work;
32         void *codec_data;
33  };
34  
35 diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
36 index 9e20333..e96930e 100644
37 --- a/sound/soc/soc-core.c
38 +++ b/sound/soc/soc-core.c
39 @@ -632,6 +632,16 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
40         struct snd_soc_codec *codec = socdev->codec;
41         int i;
42  
43 +       /* Due to the resume being scheduled into a workqueue we could
44 +       * suspend before that's finished - wait for it to complete.
45 +        */
46 +       snd_power_lock(codec->card);
47 +       snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
48 +       snd_power_unlock(codec->card);
49 +
50 +       /* we're going to block userspace touching us until resume completes */
51 +       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
52 +
53         /* mute any active DAC's */
54         for(i = 0; i < machine->num_links; i++) {
55                 struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
56 @@ -684,16 +694,27 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
57         return 0;
58  }
59  
60 -/* powers up audio subsystem after a suspend */
61 -static int soc_resume(struct platform_device *pdev)
62 +/* deferred resume work, so resume can complete before we finished
63 + * setting our codec back up, which can be very slow on I2C
64 + */
65 +static void soc_resume_deferred(struct work_struct *work)
66  {
67 -       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
68 -       struct snd_soc_machine *machine = socdev->machine;
69 -       struct snd_soc_platform *platform = socdev->platform;
70 -       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
71 +       struct snd_soc_device *socdev = container_of(work,
72 +                                                    struct snd_soc_device,
73 +                                                    deferred_resume_work);
74 +       struct snd_soc_machine *machine = socdev->machine;
75 +       struct snd_soc_platform *platform = socdev->platform;
76 +       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
77         struct snd_soc_codec *codec = socdev->codec;
78 +       struct platform_device *pdev = to_platform_device(socdev->dev);
79         int i;
80  
81 +       /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
82 +        * so userspace apps are blocked from touching us
83 +        */
84 +
85 +       dev_info(socdev->dev, "starting resume work\n");
86 +
87         if (machine->resume_pre)
88                 machine->resume_pre(pdev);
89  
90 @@ -735,6 +756,22 @@ static int soc_resume(struct platform_device *pdev)
91         if (machine->resume_post)
92                 machine->resume_post(pdev);
93  
94 +       dev_info(socdev->dev, "resume work completed\n");
95 +
96 +       /* userspace can access us now we are back as we were before */
97 +       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
98 +}
99 +
100 +/* powers up audio subsystem after a suspend */
101 +static int soc_resume(struct platform_device *pdev)
102 +{
103 +       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
104 +
105 +       dev_info(socdev->dev, "scheduling resume work\n");
106 +
107 +       if (!schedule_work(&socdev->deferred_resume_work))
108 +               dev_err(socdev->dev, "work item may be lost\n");
109 +
110         return 0;
111  }
112  
113 @@ -781,6 +818,9 @@ static int soc_probe(struct platform_device *pdev)
114  
115         /* DAPM stream work */
116         INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work);
117 +       /* deferred resume work */
118 +       INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred);
119 +
120         return 0;
121  
122  platform_err:
123 -- 
124 1.5.6.5
125