Commit 5e7c0344 authored by Daniel Mack's avatar Daniel Mack Committed by Mark Brown

ASoC: cs4270: add power management support

Signed-off-by: default avatarDaniel Mack <daniel@caiaq.de>
Acked-by: default avatarTimur Tabi <timur@freescale.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 80ab8817
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* - The machine driver's 'startup' function must call * - The machine driver's 'startup' function must call
* cs4270_set_dai_sysclk() with the value of MCLK. * cs4270_set_dai_sysclk() with the value of MCLK.
* - Only I2S and left-justified modes are supported * - Only I2S and left-justified modes are supported
* - Power management is not supported * - Power management is supported
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/initval.h> #include <sound/initval.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/delay.h>
#include "cs4270.h" #include "cs4270.h"
...@@ -65,6 +66,8 @@ ...@@ -65,6 +66,8 @@
#define CS4270_PWRCTL_PDN_ADC 0x20 #define CS4270_PWRCTL_PDN_ADC 0x20
#define CS4270_PWRCTL_PDN_DAC 0x02 #define CS4270_PWRCTL_PDN_DAC 0x02
#define CS4270_PWRCTL_PDN 0x01 #define CS4270_PWRCTL_PDN 0x01
#define CS4270_PWRCTL_PDN_ALL \
(CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN)
#define CS4270_MODE_SPEED_MASK 0x30 #define CS4270_MODE_SPEED_MASK 0x30
#define CS4270_MODE_1X 0x00 #define CS4270_MODE_1X 0x00
#define CS4270_MODE_2X 0x10 #define CS4270_MODE_2X 0x10
...@@ -788,6 +791,57 @@ static struct i2c_device_id cs4270_id[] = { ...@@ -788,6 +791,57 @@ static struct i2c_device_id cs4270_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, cs4270_id); MODULE_DEVICE_TABLE(i2c, cs4270_id);
#ifdef CONFIG_PM
/* This suspend/resume implementation can handle both - a simple standby
* where the codec remains powered, and a full suspend, where the voltage
* domain the codec is connected to is teared down and/or any other hardware
* reset condition is asserted.
*
* The codec's own power saving features are enabled in the suspend callback,
* and all registers are written back to the hardware when resuming.
*/
static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct cs4270_private *cs4270 = i2c_get_clientdata(client);
struct snd_soc_codec *codec = &cs4270->codec;
int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
return snd_soc_write(codec, CS4270_PWRCTL, reg);
}
static int cs4270_i2c_resume(struct i2c_client *client)
{
struct cs4270_private *cs4270 = i2c_get_clientdata(client);
struct snd_soc_codec *codec = &cs4270->codec;
int reg;
/* In case the device was put to hard reset during sleep, we need to
* wait 500ns here before any I2C communication. */
ndelay(500);
/* first restore the entire register cache ... */
for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) {
u8 val = snd_soc_read(codec, reg);
if (i2c_smbus_write_byte_data(client, reg, val)) {
dev_err(codec->dev, "i2c write failed\n");
return -EIO;
}
}
/* ... then disable the power-down bits */
reg = snd_soc_read(codec, CS4270_PWRCTL);
reg &= ~CS4270_PWRCTL_PDN_ALL;
return snd_soc_write(codec, CS4270_PWRCTL, reg);
}
#else
#define cs4270_i2c_suspend NULL
#define cs4270_i2c_resume NULL
#endif /* CONFIG_PM */
/* /*
* cs4270_i2c_driver - I2C device identification * cs4270_i2c_driver - I2C device identification
* *
...@@ -802,6 +856,8 @@ static struct i2c_driver cs4270_i2c_driver = { ...@@ -802,6 +856,8 @@ static struct i2c_driver cs4270_i2c_driver = {
.id_table = cs4270_id, .id_table = cs4270_id,
.probe = cs4270_i2c_probe, .probe = cs4270_i2c_probe,
.remove = cs4270_i2c_remove, .remove = cs4270_i2c_remove,
.suspend = cs4270_i2c_suspend,
.resume = cs4270_i2c_resume,
}; };
/* /*
......
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