ASoC: cs4270: add power management support
Signed-off-by: Daniel Mack <daniel@caiaq.de> Acked-by: Timur Tabi <timur@freescale.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
80ab8817bf
commit
5e7c034425
@ -18,7 +18,7 @@
|
||||
* - The machine driver's 'startup' function must call
|
||||
* cs4270_set_dai_sysclk() with the value of MCLK.
|
||||
* - Only I2S and left-justified modes are supported
|
||||
* - Power management is not supported
|
||||
* - Power management is supported
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -27,6 +27,7 @@
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "cs4270.h"
|
||||
|
||||
@ -65,6 +66,8 @@
|
||||
#define CS4270_PWRCTL_PDN_ADC 0x20
|
||||
#define CS4270_PWRCTL_PDN_DAC 0x02
|
||||
#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_1X 0x00
|
||||
#define CS4270_MODE_2X 0x10
|
||||
@ -788,6 +791,57 @@ static struct i2c_device_id 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
|
||||
*
|
||||
@ -802,6 +856,8 @@ static struct i2c_driver cs4270_i2c_driver = {
|
||||
.id_table = cs4270_id,
|
||||
.probe = cs4270_i2c_probe,
|
||||
.remove = cs4270_i2c_remove,
|
||||
.suspend = cs4270_i2c_suspend,
|
||||
.resume = cs4270_i2c_resume,
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user