summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2016-02-24 13:40:42 -0800
committerStefan Agner <stefan.agner@toradex.com>2016-02-25 15:14:02 -0800
commit661410c43938c9d74c897d8ad5aab6f95a5b9310 (patch)
treea72b2c0672378b133b90712881e30977a9a35216 /sound
parente4f69f468cb002c167ab469dbdbeab623f4aa590 (diff)
ASoC: fsl_sai_clk: add suspend/resume support
Implement suspend and resume function which disable/enable generated master clock explicitly and handle the audio clock too. Use regmap cache to restore the register content on resume from lowest power modes. Signed-off-by: Stefan Agner <stefan.agner@toradex.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/fsl/fsl_sai_clk.c55
1 files changed, 51 insertions, 4 deletions
diff --git a/sound/soc/fsl/fsl_sai_clk.c b/sound/soc/fsl/fsl_sai_clk.c
index 6b366c2aafe2..1d0b4cb5f126 100644
--- a/sound/soc/fsl/fsl_sai_clk.c
+++ b/sound/soc/fsl/fsl_sai_clk.c
@@ -97,6 +97,50 @@ static struct regmap_config fsl_sai_regmap_config = {
.readable_reg = fsl_sai_readable_reg,
.volatile_reg = fsl_sai_volatile_reg,
.writeable_reg = fsl_sai_writeable_reg,
+ .cache_type = REGCACHE_FLAT,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int fsl_sai_clk_suspend(struct device *dev)
+{
+ struct fsl_sai *sai = dev_get_drvdata(dev);
+
+ /* disable AC97 master clock */
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_BCE, 0);
+
+ regcache_cache_only(sai->regmap, true);
+
+ clk_disable_unprepare(sai->mclk_clk[1]);
+ clk_disable_unprepare(sai->bus_clk);
+
+ return 0;
+}
+
+static int fsl_sai_clk_resume(struct device *dev)
+{
+ struct fsl_sai *sai = dev_get_drvdata(dev);
+
+ clk_prepare_enable(sai->bus_clk);
+ clk_prepare_enable(sai->mclk_clk[1]);
+
+ regcache_mark_dirty(sai->regmap);
+ regcache_cache_only(sai->regmap, false);
+ regcache_sync(sai->regmap);
+
+ /* enable AC97 master clock */
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_BCE,
+ FSL_SAI_CSR_BCE);
+
+ return 0;
+}
+#else
+#define fsl_sai_clk_suspend NULL
+#define fsl_sai_clk_resume NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_sai_clk_pm = {
+ .suspend_late = fsl_sai_clk_suspend,
+ .resume_early = fsl_sai_clk_resume,
};
static int fsl_sai_clk_probe(struct platform_device *pdev)
@@ -179,16 +223,18 @@ static int fsl_sai_clk_probe(struct platform_device *pdev)
regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_DIV_MASK,
FSL_SAI_CR2_DIV(2));
- /* enable AC97 master clock */
- regmap_update_bits(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_BCE,
- FSL_SAI_CSR_BCE);
-
ret = clk_prepare_enable(sai->mclk_clk[1]);
if (ret) {
dev_err(&pdev->dev, "failed to enable mclk1: %d\n", ret);
return ret;
}
+ /* enable AC97 master clock */
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_BCE,
+ FSL_SAI_CSR_BCE);
+
+ platform_set_drvdata(pdev, sai);
+
return 0;
}
@@ -203,6 +249,7 @@ static struct platform_driver fsl_sai_driver = {
.name = "fsl-sai-clk",
.owner = THIS_MODULE,
.of_match_table = fsl_sai_ids,
+ .pm = &fsl_sai_clk_pm,
},
};
module_platform_driver(fsl_sai_driver);