LOCAL / ASoC: samsung: Add PM operation to ensure playback after PM suspend/resume
authorInha Song <ideal.song@samsung.com>
Thu, 17 Sep 2015 06:29:17 +0000 (15:29 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 14 Dec 2016 04:48:09 +0000 (13:48 +0900)
This patch add suspend/resume operation to ensure playback after
PM suspend/resume.

If you wakeup by the resume after entering to suspend during the playback,
We should be re-setup the codec's pll and sysclk to ensure codec operation.

Signed-off-by: Inha Song <ideal.song@samsung.com>
sound/soc/samsung/tm2_wm5110.c

index 2674ba2..2134367 100644 (file)
@@ -26,63 +26,32 @@ struct tm2_machine_priv {
        struct snd_soc_codec *codec;
        struct clk *codec_mclk1;
        struct clk *codec_mclk2;
+
+       unsigned int sysclk_rate;
+
        int mic_bias;
 };
 
 static struct tm2_machine_priv tm2_machine_priv;
 
-static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+static int tm2_start_sysclk(struct snd_soc_card *card)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = rtd->codec;
-       struct tm2_machine_priv *priv =
-                               snd_soc_card_get_drvdata(rtd->card);
-       unsigned int sysclk_rate;
+       struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_codec *codec = priv->codec;
        unsigned int mclk_rate =
                        (unsigned int)clk_get_rate(priv->codec_mclk1);
        int ret;
 
-       dev_dbg(codec->dev, "params_rate: %d\n", params_rate(params));
-
-       /*
-        * SYSCLK Frequency is dependent on the Sample Rate. According to
-        * the sample rate, valid SYSCLK frequency is defined in manual.
-        * The manual recommand to select the highest possible SYSCLK
-        * frequency.
-        */
-       switch (params_rate(params)) {
-       case 4000:
-       case 8000:
-       case 12000:
-       case 16000:
-       case 24000:
-       case 32000:
-       case 48000:
-       case 96000:
-       case 192000:
-               /* highest possible SYSCLK frequency: 147.456MHz */
-               sysclk_rate = 147456000;
-               break;
-       case 11025:
-       case 22050:
-       case 44100:
-       case 88200:
-       case 176400:
-               /* highest possible SYSCLK frequency: 135.4752 MHz */
-               sysclk_rate = 135475200;
-               break;
-       default:
-               dev_err(codec->dev, "Not supported sample rate: %d\n",
-                       params_rate(params));
-               return -EINVAL;
+       ret = clk_prepare_enable(priv->codec_mclk1);
+       if (ret) {
+               dev_err(card->dev, "Failed to enable mclk: %d\n", ret);
+               return ret;
        }
 
        ret = snd_soc_codec_set_pll(codec, WM5110_FLL1,
                                    ARIZONA_FLL_SRC_MCLK1,
                                    mclk_rate,
-                                   sysclk_rate);
+                                   priv->sysclk_rate);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to start FLL: %d\n", ret);
                return ret;
@@ -91,21 +60,15 @@ static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
        ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK,
                                    ARIZONA_FLL_SRC_MCLK1,
                                    mclk_rate,
-                                   sysclk_rate);
+                                   priv->sysclk_rate);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set FLL1 Source: %d\n", ret);
                return ret;
        }
 
-       ret = snd_soc_dai_set_sysclk(codec_dai, ARIZONA_CLK_SYSCLK, 0, 0);
-       if (ret < 0) {
-               dev_err(codec_dai->dev, "Failed to set SYSCLK: %d\n", ret);
-               return ret;
-       }
-
        ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
                                       ARIZONA_CLK_SRC_FLL1,
-                                      sysclk_rate,
+                                      priv->sysclk_rate,
                                       SND_SOC_CLOCK_IN);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set SYSCLK Source: %d\n", ret);
@@ -115,35 +78,82 @@ static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int tm2_start_sysclk(struct snd_soc_card *card)
+static int tm2_stop_sysclk(struct snd_soc_card *card)
 {
        struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_codec *codec = priv->codec;
        int ret;
 
-       ret = clk_prepare_enable(priv->codec_mclk1);
-       if (ret) {
-               dev_err(card->dev, "Failed to enable mclk: %d\n", ret);
+       ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to stop FLL: %d\n", ret);
                return ret;
        }
 
+       ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
+                                      ARIZONA_CLK_SRC_FLL1, 0, 0);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       clk_disable_unprepare(priv->codec_mclk1);
+
        return 0;
 }
 
-static void tm2_stop_sysclk(struct snd_soc_card *card)
+static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
 {
-       struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct tm2_machine_priv *priv =
+                               snd_soc_card_get_drvdata(rtd->card);
        int ret;
 
-       ret = snd_soc_codec_set_pll(priv->codec, WM5110_FLL1, 0, 0, 0);
-       if (ret < 0)
-               dev_err(priv->codec->dev, "Failed to stop FLL: %d\n", ret);
+       dev_dbg(codec->dev, "params_rate: %d\n", params_rate(params));
 
-       ret = snd_soc_codec_set_sysclk(priv->codec, ARIZONA_CLK_SYSCLK,
-                                      ARIZONA_CLK_SRC_FLL1, 0, 0);
-       if (ret < 0)
-               dev_err(priv->codec->dev, "Failed to stop SYSCLK: %d\n", ret);
+       /*
+        * SYSCLK Frequency is dependent on the Sample Rate. According to
+        * the sample rate, valid SYSCLK frequency is defined in manual.
+        * The manual recommand to select the highest possible SYSCLK
+        * frequency.
+        */
+       switch (params_rate(params)) {
+       case 4000:
+       case 8000:
+       case 12000:
+       case 16000:
+       case 24000:
+       case 32000:
+       case 48000:
+       case 96000:
+       case 192000:
+               /* highest possible SYSCLK frequency: 147.456MHz */
+               priv->sysclk_rate = 147456000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+       case 88200:
+       case 176400:
+               /* highest possible SYSCLK frequency: 135.4752 MHz */
+               priv->sysclk_rate = 135475200;
+               break;
+       default:
+               dev_err(codec->dev, "Not supported sample rate: %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
 
-       clk_disable_unprepare(priv->codec_mclk1);
+       ret = snd_soc_dai_set_sysclk(codec_dai, ARIZONA_CLK_SYSCLK, 0, 0);
+       if (ret < 0) {
+               dev_err(codec_dai->dev, "Failed to set SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       return tm2_start_sysclk(rtd->card);
 }
 
 static struct snd_soc_ops tm2_aif1_ops = {
@@ -331,6 +341,16 @@ static int tm2_late_probe(struct snd_soc_card *card)
        return 0;
 }
 
+static int tm2_suspend_post(struct snd_soc_card *card)
+{
+       return tm2_stop_sysclk(card);
+}
+
+static int tm2_resume_pre(struct snd_soc_card *card)
+{
+       return tm2_start_sysclk(card);
+}
+
 static const struct snd_kcontrol_new card_controls[] = {
        SOC_DAPM_PIN_SWITCH("HP"),
        SOC_DAPM_PIN_SWITCH("SPK"),
@@ -452,6 +472,9 @@ static struct snd_soc_card tm2_card = {
 
        .set_bias_level         = tm2_set_bias_level,
 
+       .suspend_post           = tm2_suspend_post,
+       .resume_pre             = tm2_resume_pre,
+
        .drvdata                = &tm2_machine_priv,
 };