1
0
Fork 0

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: Shengjiu Wang <shengjiu.wang@nxp.com>
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
alistair/sunxi64-5.4-dsi
S.j. Wang 2019-05-03 12:49:44 -07:00 committed by Mark Brown
parent 1a5c0b28fc
commit b2d337d8de
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
1 changed files with 77 additions and 64 deletions

View File

@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
@ -466,30 +467,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *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) {
/* Set synchronous mode */
@ -506,16 +483,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
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,
@ -576,20 +543,6 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
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,
struct snd_soc_dai *dai)
{
@ -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 = {
.startup = fsl_esai_startup,
.shutdown = fsl_esai_shutdown,
.trigger = fsl_esai_trigger,
.hw_params = fsl_esai_hw_params,
.set_sysclk = fsl_esai_set_dai_sysclk,
@ -947,6 +899,10 @@ static int fsl_esai_probe(struct platform_device *pdev)
return ret;
}
pm_runtime_enable(&pdev->dev);
regcache_cache_only(esai_priv->regmap, true);
ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE);
if (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)
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[] = {
{ .compatible = "fsl,imx35-esai", },
{ .compatible = "fsl,vf610-esai", },
@ -961,22 +924,35 @@ static const struct of_device_id fsl_esai_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
#ifdef CONFIG_PM_SLEEP
static int fsl_esai_suspend(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)
#ifdef CONFIG_PM
static int fsl_esai_runtime_resume(struct device *dev)
{
struct fsl_esai *esai = dev_get_drvdata(dev);
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);
/* FIFO reset for safety */
@ -987,22 +963,59 @@ static int fsl_esai_resume(struct device *dev)
ret = regcache_sync(esai->regmap);
if (ret)
return ret;
goto err_regcache_sync;
/* FIFO reset done */
regmap_update_bits(esai->regmap, REG_ESAI_TFCR, 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;
}
#endif /* CONFIG_PM_SLEEP */
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;
}
#endif /* CONFIG_PM */
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 = {
.probe = fsl_esai_probe,
.remove = fsl_esai_remove,
.driver = {
.name = "fsl-esai-dai",
.pm = &fsl_esai_pm_ops,