[alsa-devel] [PATCH 0/2] Add runtime PM for SAI digital audio interface
First patch uses system PM handlers to implement runtime PM. While the second patch moves clock handling from startup/shutdown to runtime PM handlers.
Daniel Baluta (1): ASoC: fsl: sai: Add support for runtime pm
Shengjiu Wang (1): ASoC: fsl: Move clock operation to PM runtime
sound/soc/fsl/fsl_sai.c | 70 ++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 15 deletions(-)
Basically the same actions as for system PM, so make use of pm_runtime_force_suspend/pm_runtime_force_resume.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/fsl/fsl_sai.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index b563004fb89f..aeeb07b74177 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -9,6 +9,7 @@ #include <linux/dmaengine.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/time.h> @@ -898,6 +899,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sai);
+ pm_runtime_enable(&pdev->dev); + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, &fsl_sai_dai, 1); if (ret) @@ -917,8 +920,8 @@ static const struct of_device_id fsl_sai_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_sai_ids);
-#ifdef CONFIG_PM_SLEEP -static int fsl_sai_suspend(struct device *dev) +#ifdef CONFIG_PM +static int fsl_sai_runtime_suspend(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev);
@@ -928,7 +931,7 @@ static int fsl_sai_suspend(struct device *dev) return 0; }
-static int fsl_sai_resume(struct device *dev) +static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev);
@@ -940,10 +943,13 @@ static int fsl_sai_resume(struct device *dev) regmap_write(sai->regmap, FSL_SAI_RCSR, 0); return regcache_sync(sai->regmap); } -#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */
static const struct dev_pm_ops fsl_sai_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(fsl_sai_suspend, fsl_sai_resume) + SET_RUNTIME_PM_OPS(fsl_sai_runtime_suspend, + fsl_sai_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) };
static struct platform_driver fsl_sai_driver = {
On Sat, Apr 20, 2019 at 03:59:04PM +0000, Daniel Baluta wrote:
@@ -898,6 +899,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sai);
- pm_runtime_enable(&pdev->dev);
You will need pm_runtime_disable() somewhere, like remove().
Thanks
From: Shengjiu Wang shengjiu.wang@nxp.com
Turn off/on clocks when device enters suspend/resume. This helps saving power.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/fsl/fsl_sai.c | 54 +++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index aeeb07b74177..a224c07ce31f 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -594,15 +594,8 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - struct device *dev = &sai->pdev->dev; int ret;
- ret = clk_prepare_enable(sai->bus_clk); - if (ret) { - dev_err(dev, "failed to enable bus clock: %d\n", ret); - return ret; - } - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, FSL_SAI_CR3_TRCE);
@@ -619,8 +612,6 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0); - - clk_disable_unprepare(sai->bus_clk); }
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { @@ -925,6 +916,14 @@ static int fsl_sai_runtime_suspend(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev);
+ if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); + + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); + + clk_disable_unprepare(sai->bus_clk); + regcache_cache_only(sai->regmap, true); regcache_mark_dirty(sai->regmap);
@@ -934,6 +933,25 @@ static int fsl_sai_runtime_suspend(struct device *dev) static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(sai->bus_clk); + if (ret) { + dev_err(dev, "failed to enable bus clock: %d\n", ret); + return ret; + } + + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) { + ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]); + if (ret) + goto disable_bus_clk; + } + + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) { + ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]); + if (ret) + goto disable_tx_clk; + }
regcache_cache_only(sai->regmap, false); regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); @@ -941,7 +959,23 @@ static int fsl_sai_runtime_resume(struct device *dev) usleep_range(1000, 2000); regmap_write(sai->regmap, FSL_SAI_TCSR, 0); regmap_write(sai->regmap, FSL_SAI_RCSR, 0); - return regcache_sync(sai->regmap); + + ret = regcache_sync(sai->regmap); + if (ret) + goto disable_rx_clk; + + return 0; + +disable_rx_clk: + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); +disable_tx_clk: + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); +disable_bus_clk: + clk_disable_unprepare(sai->bus_clk); + + return ret; } #endif /* CONFIG_PM */
On Sat, Apr 20, 2019 at 03:59:05PM +0000, Daniel Baluta wrote:
Turn off/on clocks when device enters suspend/resume. This helps saving power.
@@ -934,6 +933,25 @@ static int fsl_sai_runtime_suspend(struct device *dev) static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev);
- int ret;
- ret = clk_prepare_enable(sai->bus_clk);
- if (ret) {
dev_err(dev, "failed to enable bus clock: %d\n", ret);
return ret;
- }
- if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) {
ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]);
if (ret)
goto disable_bus_clk;
- }
- if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) {
ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]);
if (ret)
goto disable_tx_clk;
- }
The driver only enables mclk_clks for I2S master mode. But this change enables them for I2S slave mode also. It doesn't sound a right thing to me since we are supposed to save power?
Hi Nicolin,
On Sb, 2019-04-20 at 22:54 -0700, Nicolin Chen wrote:
On Sat, Apr 20, 2019 at 03:59:05PM +0000, Daniel Baluta wrote:
Turn off/on clocks when device enters suspend/resume. This helps saving power.
@@ -934,6 +933,25 @@ static int fsl_sai_runtime_suspend(struct device *dev) static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev);
- int ret;
- ret = clk_prepare_enable(sai->bus_clk);
- if (ret) {
dev_err(dev, "failed to enable bus clock: %d\n", ret);
return ret;
- }
- if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) {
ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]);
if (ret)
goto disable_bus_clk;
- }
- if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) {
ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]);
if (ret)
goto disable_tx_clk;
- }
The driver only enables mclk_clks for I2S master mode. But this change enables them for I2S slave mode also. It doesn't sound a right thing to me since we are supposed to save power?
This change does not enable them for I2S slave mode, please check "fsl_sai_hw_params" and "fsl_sai_hw_free" functions: the field "sai->mclk_streams" is modified only for the case when "if (!sai->is_slave_mode)";
Regards, Viorel
On Mon, Apr 22, 2019 at 11:02:22AM +0000, Viorel Suman wrote:
Hi Nicolin,
On Sb, 2019-04-20 at 22:54 -0700, Nicolin Chen wrote:
On Sat, Apr 20, 2019 at 03:59:05PM +0000, Daniel Baluta wrote:
Turn off/on clocks when device enters suspend/resume. This helps saving power.
@@ -934,6 +933,25 @@ static int fsl_sai_runtime_suspend(struct device *dev) static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev);
- int ret;
- ret = clk_prepare_enable(sai->bus_clk);
- if (ret) {
dev_err(dev, "failed to enable bus clock: %d\n", ret);
return ret;
- }
- if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) {
ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]);
if (ret)
goto disable_bus_clk;
- }
- if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) {
ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]);
if (ret)
goto disable_tx_clk;
- }
The driver only enables mclk_clks for I2S master mode. But this change enables them for I2S slave mode also. It doesn't sound a right thing to me since we are supposed to save power?
This change does not enable them for I2S slave mode, please check "fsl_sai_hw_params" and "fsl_sai_hw_free" functions: the field "sai->mclk_streams" is modified only for the case when "if (!sai->is_slave_mode)";
Thanks for the input. This should be fine then.
Nicolin
On Sat, Apr 20, 2019 at 03:59:03PM +0000, Daniel Baluta wrote:
First patch uses system PM handlers to implement runtime PM. While the second patch moves clock handling from startup/shutdown to runtime PM handlers.
ASoC: fsl: sai: Add support for runtime pm ASoC: fsl: Move clock operation to PM runtime
Both patches should use the prefix: ASoC: fsl_sai: Xxxxx yyyy
Thanks
participants (3)
-
Daniel Baluta
-
Nicolin Chen
-
Viorel Suman