[PATCH v2] 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 --- changes in v2 - remove goto in startup() - remove goto disable_spba_clk - Add Acked-by: Nicolin Chen
sound/soc/fsl/fsl_spdif.c | 117 ++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 50 deletions(-)
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 5bc0e4729341..5b2689ae63d4 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -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[] = {
On Fri, 19 Jun 2020 15:54:33 +0800, Shengjiu Wang wrote:
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.
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/1] ASoC: fsl_spdif: Add pm runtime function commit: 9cb2b3796e083169b368a7add19faec1750ad998
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (2)
-
Mark Brown
-
Shengjiu Wang