diff options
author | Daniel Mack <daniel@caiaq.de> | 2009-05-05 19:26:01 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-05-07 04:00:27 -0400 |
commit | 5e7c03442574ed0376c0621bfb0c477d79c12c71 (patch) | |
tree | 25c02cdb08cd708d06a67e012e43cd916895f4e4 /sound/soc/codecs/cs4270.c | |
parent | 80ab8817bf9b740df1f0778c41875e93151409bf (diff) |
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>
Diffstat (limited to 'sound/soc/codecs/cs4270.c')
-rw-r--r-- | sound/soc/codecs/cs4270.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 153124b2e3b1..a32b8226c8a4 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * - The machine driver's 'startup' function must call | 18 | * - The machine driver's 'startup' function must call |
19 | * cs4270_set_dai_sysclk() with the value of MCLK. | 19 | * cs4270_set_dai_sysclk() with the value of MCLK. |
20 | * - Only I2S and left-justified modes are supported | 20 | * - Only I2S and left-justified modes are supported |
21 | * - Power management is not supported | 21 | * - Power management is supported |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
@@ -27,6 +27,7 @@ | |||
27 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
28 | #include <sound/initval.h> | 28 | #include <sound/initval.h> |
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/delay.h> | ||
30 | 31 | ||
31 | #include "cs4270.h" | 32 | #include "cs4270.h" |
32 | 33 | ||
@@ -65,6 +66,8 @@ | |||
65 | #define CS4270_PWRCTL_PDN_ADC 0x20 | 66 | #define CS4270_PWRCTL_PDN_ADC 0x20 |
66 | #define CS4270_PWRCTL_PDN_DAC 0x02 | 67 | #define CS4270_PWRCTL_PDN_DAC 0x02 |
67 | #define CS4270_PWRCTL_PDN 0x01 | 68 | #define CS4270_PWRCTL_PDN 0x01 |
69 | #define CS4270_PWRCTL_PDN_ALL \ | ||
70 | (CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN) | ||
68 | #define CS4270_MODE_SPEED_MASK 0x30 | 71 | #define CS4270_MODE_SPEED_MASK 0x30 |
69 | #define CS4270_MODE_1X 0x00 | 72 | #define CS4270_MODE_1X 0x00 |
70 | #define CS4270_MODE_2X 0x10 | 73 | #define CS4270_MODE_2X 0x10 |
@@ -788,6 +791,57 @@ static struct i2c_device_id cs4270_id[] = { | |||
788 | }; | 791 | }; |
789 | MODULE_DEVICE_TABLE(i2c, cs4270_id); | 792 | MODULE_DEVICE_TABLE(i2c, cs4270_id); |
790 | 793 | ||
794 | #ifdef CONFIG_PM | ||
795 | |||
796 | /* This suspend/resume implementation can handle both - a simple standby | ||
797 | * where the codec remains powered, and a full suspend, where the voltage | ||
798 | * domain the codec is connected to is teared down and/or any other hardware | ||
799 | * reset condition is asserted. | ||
800 | * | ||
801 | * The codec's own power saving features are enabled in the suspend callback, | ||
802 | * and all registers are written back to the hardware when resuming. | ||
803 | */ | ||
804 | |||
805 | static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg) | ||
806 | { | ||
807 | struct cs4270_private *cs4270 = i2c_get_clientdata(client); | ||
808 | struct snd_soc_codec *codec = &cs4270->codec; | ||
809 | int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; | ||
810 | |||
811 | return snd_soc_write(codec, CS4270_PWRCTL, reg); | ||
812 | } | ||
813 | |||
814 | static int cs4270_i2c_resume(struct i2c_client *client) | ||
815 | { | ||
816 | struct cs4270_private *cs4270 = i2c_get_clientdata(client); | ||
817 | struct snd_soc_codec *codec = &cs4270->codec; | ||
818 | int reg; | ||
819 | |||
820 | /* In case the device was put to hard reset during sleep, we need to | ||
821 | * wait 500ns here before any I2C communication. */ | ||
822 | ndelay(500); | ||
823 | |||
824 | /* first restore the entire register cache ... */ | ||
825 | for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) { | ||
826 | u8 val = snd_soc_read(codec, reg); | ||
827 | |||
828 | if (i2c_smbus_write_byte_data(client, reg, val)) { | ||
829 | dev_err(codec->dev, "i2c write failed\n"); | ||
830 | return -EIO; | ||
831 | } | ||
832 | } | ||
833 | |||
834 | /* ... then disable the power-down bits */ | ||
835 | reg = snd_soc_read(codec, CS4270_PWRCTL); | ||
836 | reg &= ~CS4270_PWRCTL_PDN_ALL; | ||
837 | |||
838 | return snd_soc_write(codec, CS4270_PWRCTL, reg); | ||
839 | } | ||
840 | #else | ||
841 | #define cs4270_i2c_suspend NULL | ||
842 | #define cs4270_i2c_resume NULL | ||
843 | #endif /* CONFIG_PM */ | ||
844 | |||
791 | /* | 845 | /* |
792 | * cs4270_i2c_driver - I2C device identification | 846 | * cs4270_i2c_driver - I2C device identification |
793 | * | 847 | * |
@@ -802,6 +856,8 @@ static struct i2c_driver cs4270_i2c_driver = { | |||
802 | .id_table = cs4270_id, | 856 | .id_table = cs4270_id, |
803 | .probe = cs4270_i2c_probe, | 857 | .probe = cs4270_i2c_probe, |
804 | .remove = cs4270_i2c_remove, | 858 | .remove = cs4270_i2c_remove, |
859 | .suspend = cs4270_i2c_suspend, | ||
860 | .resume = cs4270_i2c_resume, | ||
805 | }; | 861 | }; |
806 | 862 | ||
807 | /* | 863 | /* |