Due to some hardware dependence issues, some devices maybe require different suspend/resume execution order for CPU and Codec DAI to make sure the hardware can work normally after executing sleep and wakeup.
In old ALSA driver, people include all suspend/resume operations of both CPU and Codec in same entries. Then they change order according to actual require. But in ASoC, we should give a chance to users to reorder CPU/Codec DAI suspend/resume instead of defining the fixed order if there are some strange hardware dependence problems.
Signed-off-by: Barry Song 21cnbao@gmail.com --- include/sound/soc.h | 4 ++++ sound/soc/soc-core.c | 48 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index b1245e3..701c362 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -494,6 +494,10 @@ struct snd_soc_card { struct snd_soc_dai_link *dai_link; int num_links;
+ /* CPU <--> Codec DAI suspend/resume order */ + int cpu_suspend_earlier; /* CPU DAI and platform suspend will be called earlier than Codec */ + int cpu_resume_earlier; /* CPU DAI and platform resume will be called earlier than Codec */ + struct snd_soc_device *socdev;
struct snd_soc_codec *codec; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2d190df..a1cc855 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -660,12 +660,14 @@ static int soc_suspend(struct device *dev) if (card->suspend_pre) card->suspend_pre(pdev, PMSG_SUSPEND);
- for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && !cpu_dai->ac97_control) - cpu_dai->suspend(cpu_dai); - if (platform->suspend) - platform->suspend(cpu_dai); + if (card->cpu_suspend_earlier) { + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + if (cpu_dai->suspend && !cpu_dai->ac97_control) + cpu_dai->suspend(cpu_dai); + if (platform->suspend) + platform->suspend(cpu_dai); + } }
/* close any waiting streams and save state */ @@ -692,6 +694,16 @@ static int soc_suspend(struct device *dev) cpu_dai->suspend(cpu_dai); }
+ if (!card->cpu_suspend_earlier) { + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + if (cpu_dai->suspend && !cpu_dai->ac97_control) + cpu_dai->suspend(cpu_dai); + if (platform->suspend) + platform->suspend(cpu_dai); + } + } + if (card->suspend_post) card->suspend_post(pdev, PMSG_SUSPEND);
@@ -728,6 +740,16 @@ static void soc_resume_deferred(struct work_struct *work) cpu_dai->resume(cpu_dai); }
+ if (card->cpu_resume_earlier) { + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + if (cpu_dai->resume && !cpu_dai->ac97_control) + cpu_dai->resume(cpu_dai); + if (platform->resume) + platform->resume(cpu_dai); + } + } + if (codec_dev->resume) codec_dev->resume(pdev);
@@ -749,12 +771,14 @@ static void soc_resume_deferred(struct work_struct *work) dai->ops->digital_mute(dai, 0); }
- for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && !cpu_dai->ac97_control) - cpu_dai->resume(cpu_dai); - if (platform->resume) - platform->resume(cpu_dai); + if (!card->cpu_resume_earlier) { + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + if (cpu_dai->resume && !cpu_dai->ac97_control) + cpu_dai->resume(cpu_dai); + if (platform->resume) + platform->resume(cpu_dai); + } }
if (card->resume_post)