From a1678b46d9d7558b2ad90abf1ce39225119997bf Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Tue, 11 Jun 2013 10:54:53 -0700 Subject: [PATCH] TEMP: CHROMIUM: ASoC: samsung: reparent mout_i2s for suspend/resume On reset, fin_pll is the parent of mout_audss and mout_audss is the parent of mout_i2s, but we reparent them to fout_epll and sclk_audio0, respectively, when setting up the audio clock hierarchy. They are both then reparented on resume when the AUDSS registers are restored. This, however, causes the machine to hang during resume. It's not clear what the exact cause is, but it's possible that they cannot be reparented at the same time or that EPLL is still unstable. Temporarily reparenting mout_i2s to mout_audss across suspend/resume so that it is not reparented when the AUDSS registers are restored appears to make suspend/resume much more stable on Pit and Snow. BUG=chrome-os-partner:20102 TEST=Can suspend/resume on Pit and Snow. Audio still works. Change-Id: I75e30b66bfc103de8aa83cc62b21a9f4a938cbb5 Signed-off-by: Andrew Bresticker Reviewed-on: https://gerrit.chromium.org/gerrit/58212 Reviewed-by: Simon Glass --- sound/soc/samsung/daisy_max98095.c | 66 ++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/sound/soc/samsung/daisy_max98095.c b/sound/soc/samsung/daisy_max98095.c index 7156266106875b..c80bb4f046db05 100644 --- a/sound/soc/samsung/daisy_max98095.c +++ b/sound/soc/samsung/daisy_max98095.c @@ -479,6 +479,70 @@ static int daisy_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int daisy_suspend_post(struct snd_soc_card *card) +{ + struct clk *mout_audss, *mout_i2s; + int ret; + + mout_audss = clk_get(card->dev, "mout_audss"); + if (IS_ERR(mout_audss)) { + pr_warn("Can't find mout_audss clock\n"); + ret = PTR_ERR(mout_audss); + goto out1; + } + mout_i2s = clk_get(card->dev, "mout_i2s"); + if (IS_ERR(mout_i2s)) { + pr_warn("Can't find mout_i2s clock\n"); + ret = PTR_ERR(mout_i2s); + goto out2; + } + + /* + * This really shouldn't fail. We probably won't come back from + * suspend if it does. + */ + ret = clk_set_parent(mout_i2s, mout_audss); + WARN_ON(ret < 0); + + clk_put(mout_i2s); +out2: + clk_put(mout_audss); +out1: + return ret; +} + +static int daisy_resume_pre(struct snd_soc_card *card) +{ + struct clk *sclk_audio0, *mout_i2s; + int ret; + + sclk_audio0 = clk_get(card->dev, "sclk_audio0"); + if (IS_ERR(sclk_audio0)) { + pr_warn("Can't find sclk_audio0 clock\n"); + ret = PTR_ERR(sclk_audio0); + goto out1; + } + mout_i2s = clk_get(card->dev, "mout_i2s"); + if (IS_ERR(mout_i2s)) { + pr_warn("Can't find mout_i2s clock\n"); + ret = PTR_ERR(mout_i2s); + goto out2; + } + + /* + * If we were able to reparent this for suspend, we ought to be + * able to change it back. + */ + ret = clk_set_parent(mout_i2s, sclk_audio0); + WARN_ON(ret < 0); + + clk_put(mout_i2s); +out2: + clk_put(sclk_audio0); +out1: + return ret; +} + static int daisy_resume_post(struct snd_soc_card *card) { if (gpio_is_valid(daisy_mic_jack_gpio.gpio)) @@ -513,6 +577,8 @@ static struct snd_soc_card daisy_snd = { .num_dapm_widgets = ARRAY_SIZE(daisy_dapm_widgets), .dapm_routes = daisy_audio_map, .num_dapm_routes = ARRAY_SIZE(daisy_audio_map), + .suspend_post = daisy_suspend_post, + .resume_pre = daisy_resume_pre, .resume_post = daisy_resume_post, };