Commit e8c8e9de authored by Claudiu Beznea's avatar Claudiu Beznea Committed by Mark Brown

ASoC: mchp-pdmc: use runtime pm for clock power saving

Implement clock power saving taking advantage of runtime PM infrastructure.
This simplifies the code and allow using the same infrastructure for
suspend to RAM functionalities.
Signed-off-by: default avatarClaudiu Beznea <claudiu.beznea@microchip.com>
Link: https://lore.kernel.org/r/20221213112851.89212-3-claudiu.beznea@microchip.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent cfec0193
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <sound/core.h> #include <sound/core.h>
...@@ -115,7 +116,6 @@ struct mchp_pdmc { ...@@ -115,7 +116,6 @@ struct mchp_pdmc {
int mic_no; int mic_no;
int sinc_order; int sinc_order;
bool audio_filter_en; bool audio_filter_en;
u8 gclk_enabled:1;
}; };
static const char *const mchp_pdmc_sinc_filter_order_text[] = { static const char *const mchp_pdmc_sinc_filter_order_text[] = {
...@@ -454,13 +454,6 @@ static int mchp_pdmc_startup(struct snd_pcm_substream *substream, ...@@ -454,13 +454,6 @@ static int mchp_pdmc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai); struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
int ret;
ret = clk_prepare_enable(dd->pclk);
if (ret) {
dev_err(dd->dev, "failed to enable the peripheral clock: %d\n", ret);
return ret;
}
regmap_write(dd->regmap, MCHP_PDMC_CR, MCHP_PDMC_CR_SWRST); regmap_write(dd->regmap, MCHP_PDMC_CR, MCHP_PDMC_CR_SWRST);
...@@ -470,14 +463,6 @@ static int mchp_pdmc_startup(struct snd_pcm_substream *substream, ...@@ -470,14 +463,6 @@ static int mchp_pdmc_startup(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static void mchp_pdmc_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
clk_disable_unprepare(dd->pclk);
}
static int mchp_pdmc_dai_probe(struct snd_soc_dai *dai) static int mchp_pdmc_dai_probe(struct snd_soc_dai *dai)
{ {
struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai); struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
...@@ -594,11 +579,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, ...@@ -594,11 +579,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i); cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i);
} }
if (dd->gclk_enabled) {
clk_disable_unprepare(dd->gclk);
dd->gclk_enabled = 0;
}
for (osr_start = dd->audio_filter_en ? 64 : 8; for (osr_start = dd->audio_filter_en ? 64 : 8;
osr_start <= 256 && best_diff_rate; osr_start *= 2) { osr_start <= 256 && best_diff_rate; osr_start *= 2) {
long round_rate; long round_rate;
...@@ -620,8 +600,12 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, ...@@ -620,8 +600,12 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
/* CLK is enabled by runtime PM. */
clk_disable_unprepare(dd->gclk);
/* set the rate */ /* set the rate */
ret = clk_set_rate(dd->gclk, gclk_rate); ret = clk_set_rate(dd->gclk, gclk_rate);
clk_prepare_enable(dd->gclk);
if (ret) { if (ret) {
dev_err(comp->dev, "unable to set rate %lu to GCLK: %d\n", dev_err(comp->dev, "unable to set rate %lu to GCLK: %d\n",
gclk_rate, ret); gclk_rate, ret);
...@@ -636,9 +620,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, ...@@ -636,9 +620,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
mr_val |= MCHP_PDMC_MR_CHUNK(dd->addr.maxburst); mr_val |= MCHP_PDMC_MR_CHUNK(dd->addr.maxburst);
dev_dbg(comp->dev, "maxburst set to %d\n", dd->addr.maxburst); dev_dbg(comp->dev, "maxburst set to %d\n", dd->addr.maxburst);
clk_prepare_enable(dd->gclk);
dd->gclk_enabled = 1;
snd_soc_component_update_bits(comp, MCHP_PDMC_MR, snd_soc_component_update_bits(comp, MCHP_PDMC_MR,
MCHP_PDMC_MR_OSR_MASK | MCHP_PDMC_MR_OSR_MASK |
MCHP_PDMC_MR_SINCORDER_MASK | MCHP_PDMC_MR_SINCORDER_MASK |
...@@ -650,19 +631,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, ...@@ -650,19 +631,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int mchp_pdmc_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
if (dd->gclk_enabled) {
clk_disable_unprepare(dd->gclk);
dd->gclk_enabled = 0;
}
return 0;
}
static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
{ {
...@@ -711,9 +679,7 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, ...@@ -711,9 +679,7 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
.set_fmt = mchp_pdmc_set_fmt, .set_fmt = mchp_pdmc_set_fmt,
.startup = mchp_pdmc_startup, .startup = mchp_pdmc_startup,
.shutdown = mchp_pdmc_shutdown,
.hw_params = mchp_pdmc_hw_params, .hw_params = mchp_pdmc_hw_params,
.hw_free = mchp_pdmc_hw_free,
.trigger = mchp_pdmc_trigger, .trigger = mchp_pdmc_trigger,
}; };
...@@ -864,6 +830,7 @@ static const struct regmap_config mchp_pdmc_regmap_config = { ...@@ -864,6 +830,7 @@ static const struct regmap_config mchp_pdmc_regmap_config = {
.readable_reg = mchp_pdmc_readable_reg, .readable_reg = mchp_pdmc_readable_reg,
.writeable_reg = mchp_pdmc_writeable_reg, .writeable_reg = mchp_pdmc_writeable_reg,
.precious_reg = mchp_pdmc_precious_reg, .precious_reg = mchp_pdmc_precious_reg,
.cache_type = REGCACHE_FLAT,
}; };
static int mchp_pdmc_dt_init(struct mchp_pdmc *dd) static int mchp_pdmc_dt_init(struct mchp_pdmc *dd)
...@@ -970,6 +937,49 @@ static struct snd_dmaengine_pcm_config mchp_pdmc_config = { ...@@ -970,6 +937,49 @@ static struct snd_dmaengine_pcm_config mchp_pdmc_config = {
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
}; };
static int mchp_pdmc_runtime_suspend(struct device *dev)
{
struct mchp_pdmc *dd = dev_get_drvdata(dev);
regcache_cache_only(dd->regmap, true);
clk_disable_unprepare(dd->gclk);
clk_disable_unprepare(dd->pclk);
return 0;
}
static int mchp_pdmc_runtime_resume(struct device *dev)
{
struct mchp_pdmc *dd = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(dd->pclk);
if (ret) {
dev_err(dd->dev,
"failed to enable the peripheral clock: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(dd->gclk);
if (ret) {
dev_err(dd->dev,
"failed to enable generic clock: %d\n", ret);
goto disable_pclk;
}
regcache_cache_only(dd->regmap, false);
regcache_mark_dirty(dd->regmap);
ret = regcache_sync(dd->regmap);
if (ret) {
regcache_cache_only(dd->regmap, true);
clk_disable_unprepare(dd->gclk);
disable_pclk:
clk_disable_unprepare(dd->pclk);
}
return ret;
}
static int mchp_pdmc_probe(struct platform_device *pdev) static int mchp_pdmc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -1039,18 +1049,25 @@ static int mchp_pdmc_probe(struct platform_device *pdev) ...@@ -1039,18 +1049,25 @@ static int mchp_pdmc_probe(struct platform_device *pdev)
dd->addr.addr = (dma_addr_t)res->start + MCHP_PDMC_RHR; dd->addr.addr = (dma_addr_t)res->start + MCHP_PDMC_RHR;
platform_set_drvdata(pdev, dd); platform_set_drvdata(pdev, dd);
pm_runtime_enable(dd->dev);
if (!pm_runtime_enabled(dd->dev)) {
ret = mchp_pdmc_runtime_resume(dd->dev);
if (ret)
return ret;
}
/* register platform */ /* register platform */
ret = devm_snd_dmaengine_pcm_register(dev, &mchp_pdmc_config, 0); ret = devm_snd_dmaengine_pcm_register(dev, &mchp_pdmc_config, 0);
if (ret) { if (ret) {
dev_err(dev, "could not register platform: %d\n", ret); dev_err(dev, "could not register platform: %d\n", ret);
return ret; goto pm_runtime_suspend;
} }
ret = devm_snd_soc_register_component(dev, &mchp_pdmc_dai_component, ret = devm_snd_soc_register_component(dev, &mchp_pdmc_dai_component,
&mchp_pdmc_dai, 1); &mchp_pdmc_dai, 1);
if (ret) { if (ret) {
dev_err(dev, "could not register CPU DAI: %d\n", ret); dev_err(dev, "could not register CPU DAI: %d\n", ret);
return ret; goto pm_runtime_suspend;
} }
/* print IP version */ /* print IP version */
...@@ -1059,6 +1076,25 @@ static int mchp_pdmc_probe(struct platform_device *pdev) ...@@ -1059,6 +1076,25 @@ static int mchp_pdmc_probe(struct platform_device *pdev)
version & MCHP_PDMC_VER_VERSION); version & MCHP_PDMC_VER_VERSION);
return 0; return 0;
pm_runtime_suspend:
if (!pm_runtime_status_suspended(dd->dev))
mchp_pdmc_runtime_suspend(dd->dev);
pm_runtime_disable(dd->dev);
return ret;
}
static int mchp_pdmc_remove(struct platform_device *pdev)
{
struct mchp_pdmc *dd = platform_get_drvdata(pdev);
if (!pm_runtime_status_suspended(dd->dev))
mchp_pdmc_runtime_suspend(dd->dev);
pm_runtime_disable(dd->dev);
return 0;
} }
static const struct of_device_id mchp_pdmc_of_match[] = { static const struct of_device_id mchp_pdmc_of_match[] = {
...@@ -1070,13 +1106,19 @@ static const struct of_device_id mchp_pdmc_of_match[] = { ...@@ -1070,13 +1106,19 @@ static const struct of_device_id mchp_pdmc_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, mchp_pdmc_of_match); MODULE_DEVICE_TABLE(of, mchp_pdmc_of_match);
static const struct dev_pm_ops mchp_pdmc_pm_ops = {
RUNTIME_PM_OPS(mchp_pdmc_runtime_suspend, mchp_pdmc_runtime_resume,
NULL)
};
static struct platform_driver mchp_pdmc_driver = { static struct platform_driver mchp_pdmc_driver = {
.driver = { .driver = {
.name = "mchp-pdmc", .name = "mchp-pdmc",
.of_match_table = of_match_ptr(mchp_pdmc_of_match), .of_match_table = of_match_ptr(mchp_pdmc_of_match),
.pm = &snd_soc_pm_ops, .pm = pm_ptr(&mchp_pdmc_pm_ops),
}, },
.probe = mchp_pdmc_probe, .probe = mchp_pdmc_probe,
.remove = mchp_pdmc_remove,
}; };
module_platform_driver(mchp_pdmc_driver); module_platform_driver(mchp_pdmc_driver);
......
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