Commit b2d337d8 authored by S.j. Wang's avatar S.j. Wang Committed by Mark Brown

ASoC: fsl_esai: Add pm runtime function

Add pm runtime support and move clock handling there.
Close the clocks at suspend to reduce the power consumption.

fsl_esai_suspend is replaced by pm_runtime_force_suspend.
fsl_esai_resume is replaced by pm_runtime_force_resume.
Signed-off-by: default avatarShengjiu Wang <shengjiu.wang@nxp.com>
Signed-off-by: default avatarNicolin Chen <nicoleotsuka@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1a5c0b28
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <sound/dmaengine_pcm.h> #include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
...@@ -466,30 +467,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, ...@@ -466,30 +467,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
int ret;
/*
* Some platforms might use the same bit to gate all three or two of
* clocks, so keep all clocks open/close at the same time for safety
*/
ret = clk_prepare_enable(esai_priv->coreclk);
if (ret)
return ret;
if (!IS_ERR(esai_priv->spbaclk)) {
ret = clk_prepare_enable(esai_priv->spbaclk);
if (ret)
goto err_spbaclk;
}
if (!IS_ERR(esai_priv->extalclk)) {
ret = clk_prepare_enable(esai_priv->extalclk);
if (ret)
goto err_extalck;
}
if (!IS_ERR(esai_priv->fsysclk)) {
ret = clk_prepare_enable(esai_priv->fsysclk);
if (ret)
goto err_fsysclk;
}
if (!dai->active) { if (!dai->active) {
/* Set synchronous mode */ /* Set synchronous mode */
...@@ -506,16 +483,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, ...@@ -506,16 +483,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
return 0; return 0;
err_fsysclk:
if (!IS_ERR(esai_priv->extalclk))
clk_disable_unprepare(esai_priv->extalclk);
err_extalck:
if (!IS_ERR(esai_priv->spbaclk))
clk_disable_unprepare(esai_priv->spbaclk);
err_spbaclk:
clk_disable_unprepare(esai_priv->coreclk);
return ret;
} }
static int fsl_esai_hw_params(struct snd_pcm_substream *substream, static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
...@@ -576,20 +543,6 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, ...@@ -576,20 +543,6 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
if (!IS_ERR(esai_priv->fsysclk))
clk_disable_unprepare(esai_priv->fsysclk);
if (!IS_ERR(esai_priv->extalclk))
clk_disable_unprepare(esai_priv->extalclk);
if (!IS_ERR(esai_priv->spbaclk))
clk_disable_unprepare(esai_priv->spbaclk);
clk_disable_unprepare(esai_priv->coreclk);
}
static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
...@@ -658,7 +611,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -658,7 +611,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
static const struct snd_soc_dai_ops fsl_esai_dai_ops = { static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
.startup = fsl_esai_startup, .startup = fsl_esai_startup,
.shutdown = fsl_esai_shutdown,
.trigger = fsl_esai_trigger, .trigger = fsl_esai_trigger,
.hw_params = fsl_esai_hw_params, .hw_params = fsl_esai_hw_params,
.set_sysclk = fsl_esai_set_dai_sysclk, .set_sysclk = fsl_esai_set_dai_sysclk,
...@@ -947,6 +899,10 @@ static int fsl_esai_probe(struct platform_device *pdev) ...@@ -947,6 +899,10 @@ static int fsl_esai_probe(struct platform_device *pdev)
return ret; return ret;
} }
pm_runtime_enable(&pdev->dev);
regcache_cache_only(esai_priv->regmap, true);
ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE); ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE);
if (ret) if (ret)
dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret); dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
...@@ -954,6 +910,13 @@ static int fsl_esai_probe(struct platform_device *pdev) ...@@ -954,6 +910,13 @@ static int fsl_esai_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int fsl_esai_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
return 0;
}
static const struct of_device_id fsl_esai_dt_ids[] = { static const struct of_device_id fsl_esai_dt_ids[] = {
{ .compatible = "fsl,imx35-esai", }, { .compatible = "fsl,imx35-esai", },
{ .compatible = "fsl,vf610-esai", }, { .compatible = "fsl,vf610-esai", },
...@@ -961,22 +924,35 @@ static const struct of_device_id fsl_esai_dt_ids[] = { ...@@ -961,22 +924,35 @@ static const struct of_device_id fsl_esai_dt_ids[] = {
}; };
MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids); MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM
static int fsl_esai_suspend(struct device *dev) static int fsl_esai_runtime_resume(struct device *dev)
{
struct fsl_esai *esai = dev_get_drvdata(dev);
regcache_cache_only(esai->regmap, true);
regcache_mark_dirty(esai->regmap);
return 0;
}
static int fsl_esai_resume(struct device *dev)
{ {
struct fsl_esai *esai = dev_get_drvdata(dev); struct fsl_esai *esai = dev_get_drvdata(dev);
int ret; int ret;
/*
* Some platforms might use the same bit to gate all three or two of
* clocks, so keep all clocks open/close at the same time for safety
*/
ret = clk_prepare_enable(esai->coreclk);
if (ret)
return ret;
if (!IS_ERR(esai->spbaclk)) {
ret = clk_prepare_enable(esai->spbaclk);
if (ret)
goto err_spbaclk;
}
if (!IS_ERR(esai->extalclk)) {
ret = clk_prepare_enable(esai->extalclk);
if (ret)
goto err_extalclk;
}
if (!IS_ERR(esai->fsysclk)) {
ret = clk_prepare_enable(esai->fsysclk);
if (ret)
goto err_fsysclk;
}
regcache_cache_only(esai->regmap, false); regcache_cache_only(esai->regmap, false);
/* FIFO reset for safety */ /* FIFO reset for safety */
...@@ -987,22 +963,59 @@ static int fsl_esai_resume(struct device *dev) ...@@ -987,22 +963,59 @@ static int fsl_esai_resume(struct device *dev)
ret = regcache_sync(esai->regmap); ret = regcache_sync(esai->regmap);
if (ret) if (ret)
return ret; goto err_regcache_sync;
/* FIFO reset done */ /* FIFO reset done */
regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0); regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0);
regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0); regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0);
return 0;
err_regcache_sync:
if (!IS_ERR(esai->fsysclk))
clk_disable_unprepare(esai->fsysclk);
err_fsysclk:
if (!IS_ERR(esai->extalclk))
clk_disable_unprepare(esai->extalclk);
err_extalclk:
if (!IS_ERR(esai->spbaclk))
clk_disable_unprepare(esai->spbaclk);
err_spbaclk:
clk_disable_unprepare(esai->coreclk);
return ret;
}
static int fsl_esai_runtime_suspend(struct device *dev)
{
struct fsl_esai *esai = dev_get_drvdata(dev);
regcache_cache_only(esai->regmap, true);
regcache_mark_dirty(esai->regmap);
if (!IS_ERR(esai->fsysclk))
clk_disable_unprepare(esai->fsysclk);
if (!IS_ERR(esai->extalclk))
clk_disable_unprepare(esai->extalclk);
if (!IS_ERR(esai->spbaclk))
clk_disable_unprepare(esai->spbaclk);
clk_disable_unprepare(esai->coreclk);
return 0; return 0;
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */
static const struct dev_pm_ops fsl_esai_pm_ops = { static const struct dev_pm_ops fsl_esai_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(fsl_esai_suspend, fsl_esai_resume) SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend,
fsl_esai_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
}; };
static struct platform_driver fsl_esai_driver = { static struct platform_driver fsl_esai_driver = {
.probe = fsl_esai_probe, .probe = fsl_esai_probe,
.remove = fsl_esai_remove,
.driver = { .driver = {
.name = "fsl-esai-dai", .name = "fsl-esai-dai",
.pm = &fsl_esai_pm_ops, .pm = &fsl_esai_pm_ops,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment