summary refs log tree commit diff
path: root/sound/soc
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-01-02 13:15:56 +0000
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-01-04 21:51:13 +0000
commit53242c68333570631a15a69842851b458eca3d99 (patch)
tree256d4b739f523fe1b523189831fc72c3b1554d81 /sound/soc
parent10505634bfa74871118a21eef8617acad00e4019 (diff)
downloadlinux-53242c68333570631a15a69842851b458eca3d99.tar.gz
ASoC: Implement suspend and resume for WM8993
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/wm8993.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 5e32f2ed5fc2..cd2bc05f78cc 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -227,6 +227,7 @@ struct wm8993_priv {
 	int class_w_users;
 	unsigned int fll_fref;
 	unsigned int fll_fout;
+	int fll_src;
 };
 
 static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg)
@@ -506,6 +507,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 
 	wm8993->fll_fref = Fref;
 	wm8993->fll_fout = Fout;
+	wm8993->fll_src = source;
 
 	return 0;
 }
@@ -1480,9 +1482,74 @@ static int wm8993_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct wm8993_priv *wm8993 = codec->private_data;
+	int fll_fout = wm8993->fll_fout;
+	int fll_fref  = wm8993->fll_fref;
+	int ret;
+
+	/* Stop the FLL in an orderly fashion */
+	ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to stop FLL\n");
+		return ret;
+	}
+
+	wm8993->fll_fout = fll_fout;
+	wm8993->fll_fref = fll_fref;
+
+	wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm8993_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct wm8993_priv *wm8993 = codec->private_data;
+	u16 *cache = wm8993->reg_cache;
+	int i, ret;
+
+	/* Restore the register settings */
+	for (i = 1; i < WM8993_MAX_REGISTER; i++) {
+		if (cache[i] == wm8993_reg_defaults[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+
+	wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* Restart the FLL? */
+	if (wm8993->fll_fout) {
+		int fll_fout = wm8993->fll_fout;
+		int fll_fref  = wm8993->fll_fref;
+
+		wm8993->fll_fref = 0;
+		wm8993->fll_fout = 0;
+
+		ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src,
+				     fll_fref, fll_fout);
+		if (ret != 0)
+			dev_err(codec->dev, "Failed to restart FLL\n");
+	}
+
+	return 0;
+}
+#else
+#define wm8993_suspend NULL
+#define wm8993_resume NULL
+#endif
+
 struct snd_soc_codec_device soc_codec_dev_wm8993 = {
 	.probe = 	wm8993_probe,
 	.remove = 	wm8993_remove,
+	.suspend =	wm8993_suspend,
+	.resume =	wm8993_resume,
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);