From: Bard Liao bardliao@realtek.com
This patch adds runtime PM support on rt5670 codec. And will switch sysclk to internal clock during runtime suspend.
Signed-off-by: Bard Liao bardliao@realtek.com --- sound/soc/codecs/rt5670.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index da4b689..97359b3 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/firmware.h> @@ -2666,6 +2667,13 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, /*Give sysclk a default value*/ rt5670->sysclk = 24576000;
+ /* The set initial power status to active, to be consist with ACPI power + * state D0. The codec will be suspended after probe and runtime status + * change will trigger ACPI D3 method for power saving. + */ + pm_runtime_set_active(&i2c->dev); + pm_runtime_enable(&i2c->dev); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670, rt5670_dai, ARRAY_SIZE(rt5670_dai)); if (ret < 0) @@ -2673,20 +2681,61 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
return 0; err: + pm_runtime_disable(&i2c->dev); + return ret; }
static int rt5670_i2c_remove(struct i2c_client *i2c) { + pm_runtime_disable(&i2c->dev); snd_soc_unregister_codec(&i2c->dev);
return 0; }
+#ifdef CONFIG_PM_RUNTIME +static void rt5670_use_internal_clk(struct rt5670_priv *rt5670) +{ + struct snd_soc_codec *codec = rt5670->codec; + + if (!codec || + (0 == rt5670->sysclk && RT5670_SCLK_S_RCCLK == rt5670->sysclk_src)) + return; + + snd_soc_update_bits(codec, RT5670_GLB_CLK, + RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK); + + rt5670->sysclk = 0; + rt5670->sysclk_src = RT5670_SCLK_S_RCCLK; +} + +static int rt5670_runtime_suspend(struct device *dev) +{ + struct rt5670_priv *rt5670 = dev_get_drvdata(dev); + + rt5670_use_internal_clk(rt5670); + return 0; +} + +static int rt5670_runtime_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops rt5670_pm = { + SET_RUNTIME_PM_OPS(rt5670_runtime_suspend, rt5670_runtime_resume, NULL) +}; +#define RT5670_PM_OPS rt5670_pm +#else +#define RT5670_PM_OPS NULL +#endif /* CONFIG_PM_RUNTIME */ + static struct i2c_driver rt5670_i2c_driver = { .driver = { .name = "rt5670", .owner = THIS_MODULE, + .pm = &RT5670_PM_OPS, }, .probe = rt5670_i2c_probe, .remove = rt5670_i2c_remove,