forked from luck/tmp_suning_uos_patched
ASoC: fsl_spdif: Add pm runtime function
Add pm runtime support and move clock handling there. Close the clocks at suspend to reduce the power consumption. fsl_spdif_suspend is replaced by pm_runtime_force_suspend. fsl_spdif_resume is replaced by pm_runtime_force_resume. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Acked-by: Nicolin Chen <nicoleotsuka@gmail.com> Link: https://lore.kernel.org/r/579c0d71e976f34f23f40daa9f1aa06c4baca2f1.1592552389.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
3499f9ad5d
commit
9cb2b3796e
|
@ -16,6 +16,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
@ -495,29 +496,14 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
|
|||
struct platform_device *pdev = spdif_priv->pdev;
|
||||
struct regmap *regmap = spdif_priv->regmap;
|
||||
u32 scr, mask;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Reset module and interrupts only for first initialization */
|
||||
if (!snd_soc_dai_active(cpu_dai)) {
|
||||
ret = clk_prepare_enable(spdif_priv->coreclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable core clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!IS_ERR(spdif_priv->spbaclk)) {
|
||||
ret = clk_prepare_enable(spdif_priv->spbaclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable spba clock\n");
|
||||
goto err_spbaclk;
|
||||
}
|
||||
}
|
||||
|
||||
ret = spdif_softreset(spdif_priv);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to soft reset\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disable all the interrupts */
|
||||
|
@ -531,18 +517,10 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
|
|||
mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
|
||||
SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
|
||||
SCR_TXFIFO_FSEL_MASK;
|
||||
for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
|
||||
ret = clk_prepare_enable(spdif_priv->txclk[i]);
|
||||
if (ret)
|
||||
goto disable_txclk;
|
||||
}
|
||||
} else {
|
||||
scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
|
||||
mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
|
||||
SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
|
||||
ret = clk_prepare_enable(spdif_priv->rxclk);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
|
||||
|
||||
|
@ -550,17 +528,6 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
|
|||
regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_txclk:
|
||||
for (i--; i >= 0; i--)
|
||||
clk_disable_unprepare(spdif_priv->txclk[i]);
|
||||
err:
|
||||
if (!IS_ERR(spdif_priv->spbaclk))
|
||||
clk_disable_unprepare(spdif_priv->spbaclk);
|
||||
err_spbaclk:
|
||||
clk_disable_unprepare(spdif_priv->coreclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
|
||||
|
@ -569,20 +536,17 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
|
||||
struct regmap *regmap = spdif_priv->regmap;
|
||||
u32 scr, mask, i;
|
||||
u32 scr, mask;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
scr = 0;
|
||||
mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
|
||||
SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
|
||||
SCR_TXFIFO_FSEL_MASK;
|
||||
for (i = 0; i < SPDIF_TXRATE_MAX; i++)
|
||||
clk_disable_unprepare(spdif_priv->txclk[i]);
|
||||
} else {
|
||||
scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO;
|
||||
mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
|
||||
SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
|
||||
clk_disable_unprepare(spdif_priv->rxclk);
|
||||
}
|
||||
regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
|
||||
|
||||
|
@ -591,9 +555,6 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
|
|||
spdif_intr_status_clear(spdif_priv);
|
||||
regmap_update_bits(regmap, REG_SPDIF_SCR,
|
||||
SCR_LOW_POWER, SCR_LOW_POWER);
|
||||
if (!IS_ERR(spdif_priv->spbaclk))
|
||||
clk_disable_unprepare(spdif_priv->spbaclk);
|
||||
clk_disable_unprepare(spdif_priv->coreclk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1350,6 +1311,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
|
|||
|
||||
/* Register with ASoC */
|
||||
dev_set_drvdata(&pdev->dev, spdif_priv);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
regcache_cache_only(spdif_priv->regmap, true);
|
||||
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
|
||||
&spdif_priv->cpu_dai_drv, 1);
|
||||
|
@ -1365,36 +1328,90 @@ static int fsl_spdif_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int fsl_spdif_suspend(struct device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int fsl_spdif_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC,
|
||||
&spdif_priv->regcache_srpc);
|
||||
|
||||
regcache_cache_only(spdif_priv->regmap, true);
|
||||
regcache_mark_dirty(spdif_priv->regmap);
|
||||
|
||||
clk_disable_unprepare(spdif_priv->rxclk);
|
||||
|
||||
for (i = 0; i < SPDIF_TXRATE_MAX; i++)
|
||||
clk_disable_unprepare(spdif_priv->txclk[i]);
|
||||
|
||||
if (!IS_ERR(spdif_priv->spbaclk))
|
||||
clk_disable_unprepare(spdif_priv->spbaclk);
|
||||
clk_disable_unprepare(spdif_priv->coreclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_spdif_resume(struct device *dev)
|
||||
static int fsl_spdif_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = clk_prepare_enable(spdif_priv->coreclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable core clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!IS_ERR(spdif_priv->spbaclk)) {
|
||||
ret = clk_prepare_enable(spdif_priv->spbaclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable spba clock\n");
|
||||
goto disable_core_clk;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
|
||||
ret = clk_prepare_enable(spdif_priv->txclk[i]);
|
||||
if (ret)
|
||||
goto disable_tx_clk;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(spdif_priv->rxclk);
|
||||
if (ret)
|
||||
goto disable_tx_clk;
|
||||
|
||||
regcache_cache_only(spdif_priv->regmap, false);
|
||||
regcache_mark_dirty(spdif_priv->regmap);
|
||||
|
||||
regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC,
|
||||
SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
|
||||
spdif_priv->regcache_srpc);
|
||||
|
||||
return regcache_sync(spdif_priv->regmap);
|
||||
ret = regcache_sync(spdif_priv->regmap);
|
||||
if (ret)
|
||||
goto disable_rx_clk;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_rx_clk:
|
||||
clk_disable_unprepare(spdif_priv->rxclk);
|
||||
disable_tx_clk:
|
||||
for (i--; i >= 0; i--)
|
||||
clk_disable_unprepare(spdif_priv->txclk[i]);
|
||||
if (!IS_ERR(spdif_priv->spbaclk))
|
||||
clk_disable_unprepare(spdif_priv->spbaclk);
|
||||
disable_core_clk:
|
||||
clk_disable_unprepare(spdif_priv->coreclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct dev_pm_ops fsl_spdif_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id fsl_spdif_dt_ids[] = {
|
||||
|
|
Loading…
Reference in New Issue
Block a user