summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorZidan Wang <zidan.wang@freescale.com>2015-10-13 18:25:19 +0800
committerZidan Wang <zidan.wang@freescale.com>2015-10-14 11:36:43 +0800
commite35e15983e14caf48dadf235bc6b33014818c62e (patch)
tree797deecf8251a8b27422b64455fd728fb6a4c985 /sound
parentdeee257ca5fdb3b275ea99f8bb3ca2e79417284a (diff)
MLK-11570-02 ASoC: wm8994: store/restore context in codec driver suspend/resume
For lpsr mode, the codec will be power down, the register value will be lost, so we should store the context at the end of codec suspend, and load the registers at the beginning of codec resume. Signed-off-by: Zidan Wang <zidan.wang@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8994.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 66aec0c3b7bb..bc26852d0aff 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -3140,9 +3140,67 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
};
#ifdef CONFIG_PM
+static void wm8994_store_context(struct wm8994 *wm8994)
+{
+ struct device *dev = wm8994->dev;
+ int ret;
+
+ /* Disable LDO pulldowns while the device is suspended if we
+ * don't know that something will be driving them. */
+ if (!wm8994->ldo_ena_always_driven)
+ wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
+ WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
+ WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD);
+
+ /* Explicitly put the device into reset in case regulators
+ * don't get disabled in order to ensure consistent restart.
+ */
+ wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
+ wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
+
+ regcache_mark_dirty(wm8994->regmap);
+
+ /* Restore GPIO registers to prevent problems with mismatched
+ * pin configurations.
+ */
+ ret = regcache_sync_region(wm8994->regmap, WM8994_GPIO_1,
+ WM8994_GPIO_11);
+ if (ret != 0)
+ dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
+
+ /* In case one of the GPIOs is used as a wake input. */
+ ret = regcache_sync_region(wm8994->regmap,
+ WM8994_INTERRUPT_STATUS_1_MASK,
+ WM8994_INTERRUPT_STATUS_1_MASK);
+ if (ret != 0)
+ dev_err(dev, "Failed to restore interrupt mask: %d\n", ret);
+
+ regcache_cache_only(wm8994->regmap, true);
+}
+
+static int wm8994_load_context(struct wm8994 *wm8994)
+{
+ struct device *dev = wm8994->dev;
+ int ret;
+
+ regcache_cache_only(wm8994->regmap, false);
+ ret = regcache_sync(wm8994->regmap);
+ if (ret != 0) {
+ dev_err(dev, "Failed to restore register map: %d\n", ret);
+ return ret;
+ }
+
+ /* Disable LDO pulldowns while the device is active */
+ wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
+ WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD, 0);
+
+ return 0;
+}
+
static int wm8994_codec_suspend(struct snd_soc_codec *codec)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994 *control = wm8994->wm8994;
int i, ret;
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
@@ -3154,16 +3212,24 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec)
i + 1, ret);
}
- wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ wm8994_store_context(control);
+ wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int wm8994_codec_resume(struct snd_soc_codec *codec)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994 *control = wm8994->wm8994;
int i, ret;
+ ret = wm8994_load_context(control);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to load context: %d\n", ret);
+ return ret;
+ }
+
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
if (!wm8994->fll_suspend[i].out)
continue;