diff options
author | Inha Song <ideal.song@samsung.com> | 2015-09-17 15:29:17 +0900 |
---|---|---|
committer | Seung-Woo Kim <sw0312.kim@samsung.com> | 2016-12-14 13:48:09 +0900 |
commit | 9920fcc9c95f3e532a25864ad3fda8f77a5ad685 (patch) | |
tree | 561f8337d9312a1e594d979f6b18df15fb491644 /sound | |
parent | feeb63d85973cc01dc2db0e3dcf108c379e9a899 (diff) |
LOCAL / ASoC: samsung: Add PM operation to ensure playback after PM suspend/resume
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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/samsung/tm2_wm5110.c | 151 |
1 files changed, 87 insertions, 64 deletions
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index 2674ba245d00..2134367f68fb 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -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, }; |