summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorInha Song <ideal.song@samsung.com>2015-09-17 15:29:17 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:48:09 +0900
commit9920fcc9c95f3e532a25864ad3fda8f77a5ad685 (patch)
tree561f8337d9312a1e594d979f6b18df15fb491644 /sound
parentfeeb63d85973cc01dc2db0e3dcf108c379e9a899 (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.c151
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,
};