Loading sound/soc/codecs/cs4270.c +57 −1 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -27,6 +27,7 @@ #include <sound/soc.h> #include <sound/initval.h> #include <linux/i2c.h> #include <linux/delay.h> #include "cs4270.h" Loading Loading @@ -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 Loading Loading @@ -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 * Loading @@ -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 Loading
sound/soc/codecs/cs4270.c +57 −1 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -27,6 +27,7 @@ #include <sound/soc.h> #include <sound/initval.h> #include <linux/i2c.h> #include <linux/delay.h> #include "cs4270.h" Loading Loading @@ -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 Loading Loading @@ -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 * Loading @@ -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