aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/tlv320aic3x.c
diff options
context:
space:
mode:
authorJarkko Nikula <jhnikula@gmail.com>2010-09-20 03:39:12 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-09-20 13:40:46 -0400
commit6c1a7d40c2237ff7690ca682336e22777c847ffe (patch)
treeab3452cd157f176b56daea63b719646ebe404382 /sound/soc/codecs/tlv320aic3x.c
parent2f24111a08d60e6db92ed2867a339ddde2195b88 (diff)
ASoC: tlv320aic3x: Add runtime regulator control to aic3x_set_bias_level
Now all the regulators are disabled when entering into SND_SOC_BIAS_OFF and enabled when coming back to SND_SOC_BIAS_STANDBY state. Currently this runtime control happens only with suspend/resume as this patch does not change the default idle behavior. This patch manages all the regulators and reset since it seems that register sync is needed even if only analog supplies AVDD and DRVDD are disabled. This was noted when the system was running with idle behavior changed and IOVDD and DVDD were on. It is not known are all the registers needed to sync or only some subset of them. Therefore patch plays safe and does always full shutdown/power-up. Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r--sound/soc/codecs/tlv320aic3x.c83
1 files changed, 65 insertions, 18 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index c60ead948ea..5f8a7c4045c 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -70,6 +70,7 @@ struct aic3x_priv {
70 unsigned int sysclk; 70 unsigned int sysclk;
71 int master; 71 int master;
72 int gpio_reset; 72 int gpio_reset;
73 int power;
73#define AIC3X_MODEL_3X 0 74#define AIC3X_MODEL_3X 0
74#define AIC3X_MODEL_33 1 75#define AIC3X_MODEL_33 1
75#define AIC3X_MODEL_3007 2 76#define AIC3X_MODEL_3007 2
@@ -1028,6 +1029,64 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
1028 return 0; 1029 return 0;
1029} 1030}
1030 1031
1032static int aic3x_init_3007(struct snd_soc_codec *codec)
1033{
1034 u8 tmp1, tmp2, *cache = codec->reg_cache;
1035
1036 /*
1037 * There is no need to cache writes to undocumented page 0xD but
1038 * respective page 0 register cache entries must be preserved
1039 */
1040 tmp1 = cache[0xD];
1041 tmp2 = cache[0x8];
1042 /* Class-D speaker driver init; datasheet p. 46 */
1043 snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
1044 snd_soc_write(codec, 0xD, 0x0D);
1045 snd_soc_write(codec, 0x8, 0x5C);
1046 snd_soc_write(codec, 0x8, 0x5D);
1047 snd_soc_write(codec, 0x8, 0x5C);
1048 snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
1049 cache[0xD] = tmp1;
1050 cache[0x8] = tmp2;
1051
1052 return 0;
1053}
1054
1055static int aic3x_set_power(struct snd_soc_codec *codec, int power)
1056{
1057 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
1058 int i, ret;
1059 u8 *cache = codec->reg_cache;
1060
1061 if (power) {
1062 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
1063 aic3x->supplies);
1064 if (ret)
1065 goto out;
1066 aic3x->power = 1;
1067 if (aic3x->gpio_reset >= 0) {
1068 udelay(1);
1069 gpio_set_value(aic3x->gpio_reset, 1);
1070 }
1071
1072 /* Sync reg_cache with the hardware */
1073 codec->cache_only = 0;
1074 for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++)
1075 snd_soc_write(codec, i, cache[i]);
1076 if (aic3x->model == AIC3X_MODEL_3007)
1077 aic3x_init_3007(codec);
1078 codec->cache_sync = 0;
1079 } else {
1080 aic3x->power = 0;
1081 if (aic3x->gpio_reset >= 0)
1082 gpio_set_value(aic3x->gpio_reset, 0);
1083 ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
1084 aic3x->supplies);
1085 }
1086out:
1087 return ret;
1088}
1089
1031static int aic3x_set_bias_level(struct snd_soc_codec *codec, 1090static int aic3x_set_bias_level(struct snd_soc_codec *codec,
1032 enum snd_soc_bias_level level) 1091 enum snd_soc_bias_level level)
1033{ 1092{
@@ -1047,6 +1106,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
1047 } 1106 }
1048 break; 1107 break;
1049 case SND_SOC_BIAS_STANDBY: 1108 case SND_SOC_BIAS_STANDBY:
1109 if (!aic3x->power)
1110 aic3x_set_power(codec, 1);
1050 if (codec->bias_level == SND_SOC_BIAS_PREPARE && 1111 if (codec->bias_level == SND_SOC_BIAS_PREPARE &&
1051 aic3x->master) { 1112 aic3x->master) {
1052 /* disable pll */ 1113 /* disable pll */
@@ -1056,6 +1117,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
1056 } 1117 }
1057 break; 1118 break;
1058 case SND_SOC_BIAS_OFF: 1119 case SND_SOC_BIAS_OFF:
1120 if (aic3x->power)
1121 aic3x_set_power(codec, 0);
1059 break; 1122 break;
1060 } 1123 }
1061 codec->bias_level = level; 1124 codec->bias_level = level;
@@ -1155,17 +1218,6 @@ static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
1155 1218
1156static int aic3x_resume(struct snd_soc_codec *codec) 1219static int aic3x_resume(struct snd_soc_codec *codec)
1157{ 1220{
1158 int i;
1159 u8 data[2];
1160 u8 *cache = codec->reg_cache;
1161
1162 /* Sync reg_cache with the hardware */
1163 for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
1164 data[0] = i;
1165 data[1] = cache[i];
1166 codec->hw_write(codec->control_data, data, 2);
1167 }
1168
1169 aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1221 aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1170 1222
1171 return 0; 1223 return 0;
@@ -1247,13 +1299,7 @@ static int aic3x_init(struct snd_soc_codec *codec)
1247 snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); 1299 snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
1248 1300
1249 if (aic3x->model == AIC3X_MODEL_3007) { 1301 if (aic3x->model == AIC3X_MODEL_3007) {
1250 /* Class-D speaker driver init; datasheet p. 46 */ 1302 aic3x_init_3007(codec);
1251 snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
1252 snd_soc_write(codec, 0xD, 0x0D);
1253 snd_soc_write(codec, 0x8, 0x5C);
1254 snd_soc_write(codec, 0x8, 0x5D);
1255 snd_soc_write(codec, 0x8, 0x5C);
1256 snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
1257 snd_soc_write(codec, CLASSD_CTRL, 0); 1303 snd_soc_write(codec, CLASSD_CTRL, 0);
1258 } 1304 }
1259 1305
@@ -1299,6 +1345,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
1299 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 1345 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
1300 goto err_enable; 1346 goto err_enable;
1301 } 1347 }
1348 aic3x->power = 1;
1302 1349
1303 if (aic3x->gpio_reset >= 0) { 1350 if (aic3x->gpio_reset >= 0) {
1304 udelay(1); 1351 udelay(1);