diff options
Diffstat (limited to 'sound/pci/ac97')
-rw-r--r-- | sound/pci/ac97/ac97_codec.c | 334 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 98 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_patch.h | 1 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_pcm.c | 18 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_proc.c | 18 | ||||
-rw-r--r-- | sound/pci/ac97/ak4531_codec.c | 49 |
6 files changed, 445 insertions, 73 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 51e83d7a839a..a79e91850ba3 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/tlv.h> | ||
34 | #include <sound/ac97_codec.h> | 35 | #include <sound/ac97_codec.h> |
35 | #include <sound/asoundef.h> | 36 | #include <sound/asoundef.h> |
36 | #include <sound/initval.h> | 37 | #include <sound/initval.h> |
@@ -47,6 +48,11 @@ static int enable_loopback; | |||
47 | module_param(enable_loopback, bool, 0444); | 48 | module_param(enable_loopback, bool, 0444); |
48 | MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); | 49 | MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); |
49 | 50 | ||
51 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
52 | static int power_save; | ||
53 | module_param(power_save, bool, 0644); | ||
54 | MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); | ||
55 | #endif | ||
50 | /* | 56 | /* |
51 | 57 | ||
52 | */ | 58 | */ |
@@ -151,7 +157,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
151 | { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk | 157 | { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk |
152 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, | 158 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, |
153 | { 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix | 159 | { 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix |
154 | { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, | 160 | { 0x50534304, 0xffffffff, "UCB1400", patch_ucb1400, NULL }, |
155 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, | 161 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, |
156 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, | 162 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, |
157 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, | 163 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, |
@@ -187,6 +193,8 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
187 | }; | 193 | }; |
188 | 194 | ||
189 | 195 | ||
196 | static void update_power_regs(struct snd_ac97 *ac97); | ||
197 | |||
190 | /* | 198 | /* |
191 | * I/O routines | 199 | * I/O routines |
192 | */ | 200 | */ |
@@ -554,6 +562,18 @@ int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
554 | } | 562 | } |
555 | err = snd_ac97_update_bits(ac97, reg, val_mask, val); | 563 | err = snd_ac97_update_bits(ac97, reg, val_mask, val); |
556 | snd_ac97_page_restore(ac97, page_save); | 564 | snd_ac97_page_restore(ac97, page_save); |
565 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
566 | /* check analog mixer power-down */ | ||
567 | if ((val_mask & 0x8000) && | ||
568 | (kcontrol->private_value & (1<<30))) { | ||
569 | if (val & 0x8000) | ||
570 | ac97->power_up &= ~(1 << (reg>>1)); | ||
571 | else | ||
572 | ac97->power_up |= 1 << (reg>>1); | ||
573 | if (power_save) | ||
574 | update_power_regs(ac97); | ||
575 | } | ||
576 | #endif | ||
557 | return err; | 577 | return err; |
558 | } | 578 | } |
559 | 579 | ||
@@ -962,6 +982,10 @@ static int snd_ac97_bus_dev_free(struct snd_device *device) | |||
962 | static int snd_ac97_free(struct snd_ac97 *ac97) | 982 | static int snd_ac97_free(struct snd_ac97 *ac97) |
963 | { | 983 | { |
964 | if (ac97) { | 984 | if (ac97) { |
985 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
986 | if (ac97->power_workq) | ||
987 | destroy_workqueue(ac97->power_workq); | ||
988 | #endif | ||
965 | snd_ac97_proc_done(ac97); | 989 | snd_ac97_proc_done(ac97); |
966 | if (ac97->bus) | 990 | if (ac97->bus) |
967 | ac97->bus->codec[ac97->num] = NULL; | 991 | ac97->bus->codec[ac97->num] = NULL; |
@@ -1117,7 +1141,9 @@ struct snd_kcontrol *snd_ac97_cnew(const struct snd_kcontrol_new *_template, str | |||
1117 | /* | 1141 | /* |
1118 | * create mute switch(es) for normal stereo controls | 1142 | * create mute switch(es) for normal stereo controls |
1119 | */ | 1143 | */ |
1120 | static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, int check_stereo, struct snd_ac97 *ac97) | 1144 | static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, |
1145 | int check_stereo, int check_amix, | ||
1146 | struct snd_ac97 *ac97) | ||
1121 | { | 1147 | { |
1122 | struct snd_kcontrol *kctl; | 1148 | struct snd_kcontrol *kctl; |
1123 | int err; | 1149 | int err; |
@@ -1137,10 +1163,14 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, | |||
1137 | } | 1163 | } |
1138 | if (mute_mask == 0x8080) { | 1164 | if (mute_mask == 0x8080) { |
1139 | struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); | 1165 | struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); |
1166 | if (check_amix) | ||
1167 | tmp.private_value |= (1 << 30); | ||
1140 | tmp.index = ac97->num; | 1168 | tmp.index = ac97->num; |
1141 | kctl = snd_ctl_new1(&tmp, ac97); | 1169 | kctl = snd_ctl_new1(&tmp, ac97); |
1142 | } else { | 1170 | } else { |
1143 | struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); | 1171 | struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); |
1172 | if (check_amix) | ||
1173 | tmp.private_value |= (1 << 30); | ||
1144 | tmp.index = ac97->num; | 1174 | tmp.index = ac97->num; |
1145 | kctl = snd_ctl_new1(&tmp, ac97); | 1175 | kctl = snd_ctl_new1(&tmp, ac97); |
1146 | } | 1176 | } |
@@ -1153,6 +1183,32 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, | |||
1153 | } | 1183 | } |
1154 | 1184 | ||
1155 | /* | 1185 | /* |
1186 | * set dB information | ||
1187 | */ | ||
1188 | static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); | ||
1189 | static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | ||
1190 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
1191 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
1192 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
1193 | |||
1194 | static unsigned int *find_db_scale(unsigned int maxval) | ||
1195 | { | ||
1196 | switch (maxval) { | ||
1197 | case 0x0f: return db_scale_4bit; | ||
1198 | case 0x1f: return db_scale_5bit; | ||
1199 | case 0x3f: return db_scale_6bit; | ||
1200 | } | ||
1201 | return NULL; | ||
1202 | } | ||
1203 | |||
1204 | static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv) | ||
1205 | { | ||
1206 | kctl->tlv.p = tlv; | ||
1207 | if (tlv) | ||
1208 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1209 | } | ||
1210 | |||
1211 | /* | ||
1156 | * create a volume for normal stereo/mono controls | 1212 | * create a volume for normal stereo/mono controls |
1157 | */ | 1213 | */ |
1158 | static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max, | 1214 | static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max, |
@@ -1174,6 +1230,10 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne | |||
1174 | tmp.index = ac97->num; | 1230 | tmp.index = ac97->num; |
1175 | kctl = snd_ctl_new1(&tmp, ac97); | 1231 | kctl = snd_ctl_new1(&tmp, ac97); |
1176 | } | 1232 | } |
1233 | if (reg >= AC97_PHONE && reg <= AC97_PCM) | ||
1234 | set_tlv_db_scale(kctl, db_scale_5bit_12db_max); | ||
1235 | else | ||
1236 | set_tlv_db_scale(kctl, find_db_scale(lo_max)); | ||
1177 | err = snd_ctl_add(card, kctl); | 1237 | err = snd_ctl_add(card, kctl); |
1178 | if (err < 0) | 1238 | if (err < 0) |
1179 | return err; | 1239 | return err; |
@@ -1186,7 +1246,9 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne | |||
1186 | /* | 1246 | /* |
1187 | * create a mute-switch and a volume for normal stereo/mono controls | 1247 | * create a mute-switch and a volume for normal stereo/mono controls |
1188 | */ | 1248 | */ |
1189 | static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, struct snd_ac97 *ac97) | 1249 | static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, |
1250 | int reg, int check_stereo, int check_amix, | ||
1251 | struct snd_ac97 *ac97) | ||
1190 | { | 1252 | { |
1191 | int err; | 1253 | int err; |
1192 | char name[44]; | 1254 | char name[44]; |
@@ -1197,7 +1259,9 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int | |||
1197 | 1259 | ||
1198 | if (snd_ac97_try_bit(ac97, reg, 15)) { | 1260 | if (snd_ac97_try_bit(ac97, reg, 15)) { |
1199 | sprintf(name, "%s Switch", pfx); | 1261 | sprintf(name, "%s Switch", pfx); |
1200 | if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0) | 1262 | if ((err = snd_ac97_cmute_new_stereo(card, name, reg, |
1263 | check_stereo, check_amix, | ||
1264 | ac97)) < 0) | ||
1201 | return err; | 1265 | return err; |
1202 | } | 1266 | } |
1203 | check_volume_resolution(ac97, reg, &lo_max, &hi_max); | 1267 | check_volume_resolution(ac97, reg, &lo_max, &hi_max); |
@@ -1209,8 +1273,10 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int | |||
1209 | return 0; | 1273 | return 0; |
1210 | } | 1274 | } |
1211 | 1275 | ||
1212 | #define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97) | 1276 | #define snd_ac97_cmix_new(card, pfx, reg, acheck, ac97) \ |
1213 | #define snd_ac97_cmute_new(card, name, reg, ac97) snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97) | 1277 | snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97) |
1278 | #define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \ | ||
1279 | snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97) | ||
1214 | 1280 | ||
1215 | static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97); | 1281 | static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97); |
1216 | 1282 | ||
@@ -1226,9 +1292,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1226 | /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */ | 1292 | /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */ |
1227 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { | 1293 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { |
1228 | if (ac97->flags & AC97_HAS_NO_MASTER_VOL) | 1294 | if (ac97->flags & AC97_HAS_NO_MASTER_VOL) |
1229 | err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, ac97); | 1295 | err = snd_ac97_cmute_new(card, "Master Playback Switch", |
1296 | AC97_MASTER, 0, ac97); | ||
1230 | else | 1297 | else |
1231 | err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97); | 1298 | err = snd_ac97_cmix_new(card, "Master Playback", |
1299 | AC97_MASTER, 0, ac97); | ||
1232 | if (err < 0) | 1300 | if (err < 0) |
1233 | return err; | 1301 | return err; |
1234 | } | 1302 | } |
@@ -1245,6 +1313,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1245 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); | 1313 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); |
1246 | kctl->private_value &= ~(0xff << 16); | 1314 | kctl->private_value &= ~(0xff << 16); |
1247 | kctl->private_value |= (int)max << 16; | 1315 | kctl->private_value |= (int)max << 16; |
1316 | set_tlv_db_scale(kctl, find_db_scale(max)); | ||
1248 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max); | 1317 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max); |
1249 | } | 1318 | } |
1250 | 1319 | ||
@@ -1258,6 +1327,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1258 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); | 1327 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); |
1259 | kctl->private_value &= ~(0xff << 16); | 1328 | kctl->private_value &= ~(0xff << 16); |
1260 | kctl->private_value |= (int)max << 16; | 1329 | kctl->private_value |= (int)max << 16; |
1330 | set_tlv_db_scale(kctl, find_db_scale(max)); | ||
1261 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8); | 1331 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8); |
1262 | } | 1332 | } |
1263 | 1333 | ||
@@ -1265,19 +1335,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1265 | if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) | 1335 | if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) |
1266 | && !(ac97->flags & AC97_AD_MULTI)) { | 1336 | && !(ac97->flags & AC97_AD_MULTI)) { |
1267 | /* Surround Master (0x38) is with stereo mutes */ | 1337 | /* Surround Master (0x38) is with stereo mutes */ |
1268 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0) | 1338 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", |
1339 | AC97_SURROUND_MASTER, 1, 0, | ||
1340 | ac97)) < 0) | ||
1269 | return err; | 1341 | return err; |
1270 | } | 1342 | } |
1271 | 1343 | ||
1272 | /* build headphone controls */ | 1344 | /* build headphone controls */ |
1273 | if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { | 1345 | if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { |
1274 | if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0) | 1346 | if ((err = snd_ac97_cmix_new(card, "Headphone Playback", |
1347 | AC97_HEADPHONE, 0, ac97)) < 0) | ||
1275 | return err; | 1348 | return err; |
1276 | } | 1349 | } |
1277 | 1350 | ||
1278 | /* build master mono controls */ | 1351 | /* build master mono controls */ |
1279 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { | 1352 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { |
1280 | if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, ac97)) < 0) | 1353 | if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", |
1354 | AC97_MASTER_MONO, 0, ac97)) < 0) | ||
1281 | return err; | 1355 | return err; |
1282 | } | 1356 | } |
1283 | 1357 | ||
@@ -1301,8 +1375,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1301 | ((ac97->flags & AC97_HAS_PC_BEEP) || | 1375 | ((ac97->flags & AC97_HAS_PC_BEEP) || |
1302 | snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { | 1376 | snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { |
1303 | for (idx = 0; idx < 2; idx++) | 1377 | for (idx = 0; idx < 2; idx++) |
1304 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) | 1378 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) |
1305 | return err; | 1379 | return err; |
1380 | set_tlv_db_scale(kctl, db_scale_4bit); | ||
1306 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, | 1381 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, |
1307 | snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); | 1382 | snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); |
1308 | } | 1383 | } |
@@ -1310,7 +1385,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1310 | /* build Phone controls */ | 1385 | /* build Phone controls */ |
1311 | if (!(ac97->flags & AC97_HAS_NO_PHONE)) { | 1386 | if (!(ac97->flags & AC97_HAS_NO_PHONE)) { |
1312 | if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { | 1387 | if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { |
1313 | if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0) | 1388 | if ((err = snd_ac97_cmix_new(card, "Phone Playback", |
1389 | AC97_PHONE, 1, ac97)) < 0) | ||
1314 | return err; | 1390 | return err; |
1315 | } | 1391 | } |
1316 | } | 1392 | } |
@@ -1318,7 +1394,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1318 | /* build MIC controls */ | 1394 | /* build MIC controls */ |
1319 | if (!(ac97->flags & AC97_HAS_NO_MIC)) { | 1395 | if (!(ac97->flags & AC97_HAS_NO_MIC)) { |
1320 | if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { | 1396 | if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { |
1321 | if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0) | 1397 | if ((err = snd_ac97_cmix_new(card, "Mic Playback", |
1398 | AC97_MIC, 1, ac97)) < 0) | ||
1322 | return err; | 1399 | return err; |
1323 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) | 1400 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) |
1324 | return err; | 1401 | return err; |
@@ -1327,14 +1404,16 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1327 | 1404 | ||
1328 | /* build Line controls */ | 1405 | /* build Line controls */ |
1329 | if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { | 1406 | if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { |
1330 | if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0) | 1407 | if ((err = snd_ac97_cmix_new(card, "Line Playback", |
1408 | AC97_LINE, 1, ac97)) < 0) | ||
1331 | return err; | 1409 | return err; |
1332 | } | 1410 | } |
1333 | 1411 | ||
1334 | /* build CD controls */ | 1412 | /* build CD controls */ |
1335 | if (!(ac97->flags & AC97_HAS_NO_CD)) { | 1413 | if (!(ac97->flags & AC97_HAS_NO_CD)) { |
1336 | if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { | 1414 | if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { |
1337 | if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0) | 1415 | if ((err = snd_ac97_cmix_new(card, "CD Playback", |
1416 | AC97_CD, 1, ac97)) < 0) | ||
1338 | return err; | 1417 | return err; |
1339 | } | 1418 | } |
1340 | } | 1419 | } |
@@ -1342,7 +1421,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1342 | /* build Video controls */ | 1421 | /* build Video controls */ |
1343 | if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { | 1422 | if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { |
1344 | if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { | 1423 | if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { |
1345 | if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0) | 1424 | if ((err = snd_ac97_cmix_new(card, "Video Playback", |
1425 | AC97_VIDEO, 1, ac97)) < 0) | ||
1346 | return err; | 1426 | return err; |
1347 | } | 1427 | } |
1348 | } | 1428 | } |
@@ -1350,7 +1430,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1350 | /* build Aux controls */ | 1430 | /* build Aux controls */ |
1351 | if (!(ac97->flags & AC97_HAS_NO_AUX)) { | 1431 | if (!(ac97->flags & AC97_HAS_NO_AUX)) { |
1352 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { | 1432 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { |
1353 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) | 1433 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", |
1434 | AC97_AUX, 1, ac97)) < 0) | ||
1354 | return err; | 1435 | return err; |
1355 | } | 1436 | } |
1356 | } | 1437 | } |
@@ -1363,31 +1444,38 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1363 | else | 1444 | else |
1364 | init_val = 0x9f1f; | 1445 | init_val = 0x9f1f; |
1365 | for (idx = 0; idx < 2; idx++) | 1446 | for (idx = 0; idx < 2; idx++) |
1366 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) | 1447 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) |
1367 | return err; | 1448 | return err; |
1449 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1368 | ac97->spec.ad18xx.pcmreg[0] = init_val; | 1450 | ac97->spec.ad18xx.pcmreg[0] = init_val; |
1369 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { | 1451 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { |
1370 | for (idx = 0; idx < 2; idx++) | 1452 | for (idx = 0; idx < 2; idx++) |
1371 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) | 1453 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) |
1372 | return err; | 1454 | return err; |
1455 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1373 | ac97->spec.ad18xx.pcmreg[1] = init_val; | 1456 | ac97->spec.ad18xx.pcmreg[1] = init_val; |
1374 | } | 1457 | } |
1375 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { | 1458 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { |
1376 | for (idx = 0; idx < 2; idx++) | 1459 | for (idx = 0; idx < 2; idx++) |
1377 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) | 1460 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) |
1378 | return err; | 1461 | return err; |
1462 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1379 | for (idx = 0; idx < 2; idx++) | 1463 | for (idx = 0; idx < 2; idx++) |
1380 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) | 1464 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) |
1381 | return err; | 1465 | return err; |
1466 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1382 | ac97->spec.ad18xx.pcmreg[2] = init_val; | 1467 | ac97->spec.ad18xx.pcmreg[2] = init_val; |
1383 | } | 1468 | } |
1384 | snd_ac97_write_cache(ac97, AC97_PCM, init_val); | 1469 | snd_ac97_write_cache(ac97, AC97_PCM, init_val); |
1385 | } else { | 1470 | } else { |
1386 | if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { | 1471 | if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { |
1387 | if (ac97->flags & AC97_HAS_NO_PCM_VOL) | 1472 | if (ac97->flags & AC97_HAS_NO_PCM_VOL) |
1388 | err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97); | 1473 | err = snd_ac97_cmute_new(card, |
1474 | "PCM Playback Switch", | ||
1475 | AC97_PCM, 0, ac97); | ||
1389 | else | 1476 | else |
1390 | err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97); | 1477 | err = snd_ac97_cmix_new(card, "PCM Playback", |
1478 | AC97_PCM, 0, ac97); | ||
1391 | if (err < 0) | 1479 | if (err < 0) |
1392 | return err; | 1480 | return err; |
1393 | } | 1481 | } |
@@ -1398,19 +1486,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1398 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) | 1486 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) |
1399 | return err; | 1487 | return err; |
1400 | if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { | 1488 | if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { |
1401 | if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0) | 1489 | err = snd_ac97_cmute_new(card, "Capture Switch", |
1490 | AC97_REC_GAIN, 0, ac97); | ||
1491 | if (err < 0) | ||
1402 | return err; | 1492 | return err; |
1403 | } | 1493 | } |
1404 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) | 1494 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) |
1405 | return err; | 1495 | return err; |
1496 | set_tlv_db_scale(kctl, db_scale_rec_gain); | ||
1406 | snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); | 1497 | snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); |
1407 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); | 1498 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); |
1408 | } | 1499 | } |
1409 | /* build MIC Capture controls */ | 1500 | /* build MIC Capture controls */ |
1410 | if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { | 1501 | if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { |
1411 | for (idx = 0; idx < 2; idx++) | 1502 | for (idx = 0; idx < 2; idx++) |
1412 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) | 1503 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) |
1413 | return err; | 1504 | return err; |
1505 | set_tlv_db_scale(kctl, db_scale_rec_gain); | ||
1414 | snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); | 1506 | snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); |
1415 | } | 1507 | } |
1416 | 1508 | ||
@@ -1481,6 +1573,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1481 | } | 1573 | } |
1482 | 1574 | ||
1483 | /* build S/PDIF controls */ | 1575 | /* build S/PDIF controls */ |
1576 | |||
1577 | /* Hack for ASUS P5P800-VM, which does not indicate S/PDIF capability */ | ||
1578 | if (ac97->subsystem_vendor == 0x1043 && | ||
1579 | ac97->subsystem_device == 0x810f) | ||
1580 | ac97->ext_id |= AC97_EI_SPDIF; | ||
1581 | |||
1484 | if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) { | 1582 | if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) { |
1485 | if (ac97->build_ops->build_spdif) { | 1583 | if (ac97->build_ops->build_spdif) { |
1486 | if ((err = ac97->build_ops->build_spdif(ac97)) < 0) | 1584 | if ((err = ac97->build_ops->build_spdif(ac97)) < 0) |
@@ -1817,18 +1915,25 @@ static int snd_ac97_dev_register(struct snd_device *device) | |||
1817 | return 0; | 1915 | return 0; |
1818 | } | 1916 | } |
1819 | 1917 | ||
1820 | /* unregister ac97 codec */ | 1918 | /* disconnect ac97 codec */ |
1821 | static int snd_ac97_dev_unregister(struct snd_device *device) | 1919 | static int snd_ac97_dev_disconnect(struct snd_device *device) |
1822 | { | 1920 | { |
1823 | struct snd_ac97 *ac97 = device->device_data; | 1921 | struct snd_ac97 *ac97 = device->device_data; |
1824 | if (ac97->dev.bus) | 1922 | if (ac97->dev.bus) |
1825 | device_unregister(&ac97->dev); | 1923 | device_unregister(&ac97->dev); |
1826 | return snd_ac97_free(ac97); | 1924 | return 0; |
1827 | } | 1925 | } |
1828 | 1926 | ||
1829 | /* build_ops to do nothing */ | 1927 | /* build_ops to do nothing */ |
1830 | static struct snd_ac97_build_ops null_build_ops; | 1928 | static struct snd_ac97_build_ops null_build_ops; |
1831 | 1929 | ||
1930 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
1931 | static void do_update_power(void *data) | ||
1932 | { | ||
1933 | update_power_regs(data); | ||
1934 | } | ||
1935 | #endif | ||
1936 | |||
1832 | /** | 1937 | /** |
1833 | * snd_ac97_mixer - create an Codec97 component | 1938 | * snd_ac97_mixer - create an Codec97 component |
1834 | * @bus: the AC97 bus which codec is attached to | 1939 | * @bus: the AC97 bus which codec is attached to |
@@ -1860,7 +1965,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
1860 | static struct snd_device_ops ops = { | 1965 | static struct snd_device_ops ops = { |
1861 | .dev_free = snd_ac97_dev_free, | 1966 | .dev_free = snd_ac97_dev_free, |
1862 | .dev_register = snd_ac97_dev_register, | 1967 | .dev_register = snd_ac97_dev_register, |
1863 | .dev_unregister = snd_ac97_dev_unregister, | 1968 | .dev_disconnect = snd_ac97_dev_disconnect, |
1864 | }; | 1969 | }; |
1865 | 1970 | ||
1866 | snd_assert(rac97 != NULL, return -EINVAL); | 1971 | snd_assert(rac97 != NULL, return -EINVAL); |
@@ -1883,6 +1988,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
1883 | bus->codec[ac97->num] = ac97; | 1988 | bus->codec[ac97->num] = ac97; |
1884 | mutex_init(&ac97->reg_mutex); | 1989 | mutex_init(&ac97->reg_mutex); |
1885 | mutex_init(&ac97->page_mutex); | 1990 | mutex_init(&ac97->page_mutex); |
1991 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
1992 | ac97->power_workq = create_workqueue("ac97"); | ||
1993 | INIT_WORK(&ac97->power_work, do_update_power, ac97); | ||
1994 | #endif | ||
1886 | 1995 | ||
1887 | #ifdef CONFIG_PCI | 1996 | #ifdef CONFIG_PCI |
1888 | if (ac97->pci) { | 1997 | if (ac97->pci) { |
@@ -2117,15 +2226,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
2117 | return -ENOMEM; | 2226 | return -ENOMEM; |
2118 | } | 2227 | } |
2119 | } | 2228 | } |
2120 | /* make sure the proper powerdown bits are cleared */ | 2229 | if (ac97_is_audio(ac97)) |
2121 | if (ac97->scaps && ac97_is_audio(ac97)) { | 2230 | update_power_regs(ac97); |
2122 | reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); | ||
2123 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2124 | reg &= ~AC97_EA_PRJ; | ||
2125 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2126 | reg &= ~(AC97_EA_PRI | AC97_EA_PRK); | ||
2127 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg); | ||
2128 | } | ||
2129 | snd_ac97_proc_init(ac97); | 2231 | snd_ac97_proc_init(ac97); |
2130 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { | 2232 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { |
2131 | snd_ac97_free(ac97); | 2233 | snd_ac97_free(ac97); |
@@ -2153,19 +2255,152 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) | |||
2153 | snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f); | 2255 | snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f); |
2154 | } | 2256 | } |
2155 | 2257 | ||
2156 | power = ac97->regs[AC97_POWERDOWN] | 0x8000; /* EAPD */ | 2258 | /* surround, CLFE, mic powerdown */ |
2157 | power |= 0x4000; /* Headphone amplifier powerdown */ | 2259 | power = ac97->regs[AC97_EXTENDED_STATUS]; |
2158 | power |= 0x0300; /* ADC & DAC powerdown */ | 2260 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) |
2159 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2261 | power |= AC97_EA_PRJ; |
2160 | udelay(100); | 2262 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) |
2161 | power |= 0x0400; /* Analog Mixer powerdown (Vref on) */ | 2263 | power |= AC97_EA_PRI | AC97_EA_PRK; |
2264 | power |= AC97_EA_PRL; | ||
2265 | snd_ac97_write(ac97, AC97_EXTENDED_STATUS, power); | ||
2266 | |||
2267 | /* powerdown external amplifier */ | ||
2268 | if (ac97->scaps & AC97_SCAP_INV_EAPD) | ||
2269 | power = ac97->regs[AC97_POWERDOWN] & ~AC97_PD_EAPD; | ||
2270 | else if (! (ac97->scaps & AC97_SCAP_EAPD_LED)) | ||
2271 | power = ac97->regs[AC97_POWERDOWN] | AC97_PD_EAPD; | ||
2272 | power |= AC97_PD_PR6; /* Headphone amplifier powerdown */ | ||
2273 | power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ | ||
2162 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2274 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2163 | udelay(100); | 2275 | udelay(100); |
2164 | #if 0 | 2276 | power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ |
2165 | /* FIXME: this causes click noises on some boards at resume */ | ||
2166 | power |= 0x3800; /* AC-link powerdown, internal Clk disable */ | ||
2167 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2277 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2278 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2279 | if (power_save) { | ||
2280 | udelay(100); | ||
2281 | /* AC-link powerdown, internal Clk disable */ | ||
2282 | /* FIXME: this may cause click noises on some boards */ | ||
2283 | power |= AC97_PD_PR4 | AC97_PD_PR5; | ||
2284 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | ||
2285 | } | ||
2286 | #endif | ||
2287 | } | ||
2288 | |||
2289 | |||
2290 | struct ac97_power_reg { | ||
2291 | unsigned short reg; | ||
2292 | unsigned short power_reg; | ||
2293 | unsigned short mask; | ||
2294 | }; | ||
2295 | |||
2296 | enum { PWIDX_ADC, PWIDX_FRONT, PWIDX_CLFE, PWIDX_SURR, PWIDX_MIC, PWIDX_SIZE }; | ||
2297 | |||
2298 | static struct ac97_power_reg power_regs[PWIDX_SIZE] = { | ||
2299 | [PWIDX_ADC] = { AC97_PCM_LR_ADC_RATE, AC97_POWERDOWN, AC97_PD_PR0}, | ||
2300 | [PWIDX_FRONT] = { AC97_PCM_FRONT_DAC_RATE, AC97_POWERDOWN, AC97_PD_PR1}, | ||
2301 | [PWIDX_CLFE] = { AC97_PCM_LFE_DAC_RATE, AC97_EXTENDED_STATUS, | ||
2302 | AC97_EA_PRI | AC97_EA_PRK}, | ||
2303 | [PWIDX_SURR] = { AC97_PCM_SURR_DAC_RATE, AC97_EXTENDED_STATUS, | ||
2304 | AC97_EA_PRJ}, | ||
2305 | [PWIDX_MIC] = { AC97_PCM_MIC_ADC_RATE, AC97_EXTENDED_STATUS, | ||
2306 | AC97_EA_PRL}, | ||
2307 | }; | ||
2308 | |||
2309 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2310 | /** | ||
2311 | * snd_ac97_update_power - update the powerdown register | ||
2312 | * @ac97: the codec instance | ||
2313 | * @reg: the rate register, e.g. AC97_PCM_FRONT_DAC_RATE | ||
2314 | * @powerup: non-zero when power up the part | ||
2315 | * | ||
2316 | * Update the AC97 powerdown register bits of the given part. | ||
2317 | */ | ||
2318 | int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) | ||
2319 | { | ||
2320 | int i; | ||
2321 | |||
2322 | if (! ac97) | ||
2323 | return 0; | ||
2324 | |||
2325 | if (reg) { | ||
2326 | /* SPDIF requires DAC power, too */ | ||
2327 | if (reg == AC97_SPDIF) | ||
2328 | reg = AC97_PCM_FRONT_DAC_RATE; | ||
2329 | for (i = 0; i < PWIDX_SIZE; i++) { | ||
2330 | if (power_regs[i].reg == reg) { | ||
2331 | if (powerup) | ||
2332 | ac97->power_up |= (1 << i); | ||
2333 | else | ||
2334 | ac97->power_up &= ~(1 << i); | ||
2335 | break; | ||
2336 | } | ||
2337 | } | ||
2338 | } | ||
2339 | |||
2340 | if (! power_save) | ||
2341 | return 0; | ||
2342 | |||
2343 | if (! powerup && ac97->power_workq) | ||
2344 | /* adjust power-down bits after two seconds delay | ||
2345 | * (for avoiding loud click noises for many (OSS) apps | ||
2346 | * that open/close frequently) | ||
2347 | */ | ||
2348 | queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2); | ||
2349 | else | ||
2350 | update_power_regs(ac97); | ||
2351 | |||
2352 | return 0; | ||
2353 | } | ||
2354 | |||
2355 | EXPORT_SYMBOL(snd_ac97_update_power); | ||
2356 | #endif /* CONFIG_SND_AC97_POWER_SAVE */ | ||
2357 | |||
2358 | static void update_power_regs(struct snd_ac97 *ac97) | ||
2359 | { | ||
2360 | unsigned int power_up, bits; | ||
2361 | int i; | ||
2362 | |||
2363 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2364 | if (power_save) | ||
2365 | power_up = ac97->power_up; | ||
2366 | else { | ||
2168 | #endif | 2367 | #endif |
2368 | power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); | ||
2369 | power_up |= (1 << PWIDX_MIC); | ||
2370 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2371 | power_up |= (1 << PWIDX_SURR); | ||
2372 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2373 | power_up |= (1 << PWIDX_CLFE); | ||
2374 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2375 | } | ||
2376 | #endif | ||
2377 | if (power_up) { | ||
2378 | if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) { | ||
2379 | /* needs power-up analog mix and vref */ | ||
2380 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2381 | AC97_PD_PR3, 0); | ||
2382 | msleep(1); | ||
2383 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2384 | AC97_PD_PR2, 0); | ||
2385 | } | ||
2386 | } | ||
2387 | for (i = 0; i < PWIDX_SIZE; i++) { | ||
2388 | if (power_up & (1 << i)) | ||
2389 | bits = 0; | ||
2390 | else | ||
2391 | bits = power_regs[i].mask; | ||
2392 | snd_ac97_update_bits(ac97, power_regs[i].power_reg, | ||
2393 | power_regs[i].mask, bits); | ||
2394 | } | ||
2395 | if (! power_up) { | ||
2396 | if (! (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2)) { | ||
2397 | /* power down analog mix and vref */ | ||
2398 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2399 | AC97_PD_PR2, AC97_PD_PR2); | ||
2400 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2401 | AC97_PD_PR3, AC97_PD_PR3); | ||
2402 | } | ||
2403 | } | ||
2169 | } | 2404 | } |
2170 | 2405 | ||
2171 | 2406 | ||
@@ -2484,6 +2719,7 @@ static int tune_mute_led(struct snd_ac97 *ac97) | |||
2484 | msw->put = master_mute_sw_put; | 2719 | msw->put = master_mute_sw_put; |
2485 | snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); | 2720 | snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); |
2486 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ | 2721 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ |
2722 | ac97->scaps |= AC97_SCAP_EAPD_LED; | ||
2487 | return 0; | 2723 | return 0; |
2488 | } | 2724 | } |
2489 | 2725 | ||
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 094cfc1f3a19..dc28b111a06d 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/control.h> | 34 | #include <sound/control.h> |
35 | #include <sound/tlv.h> | ||
35 | #include <sound/ac97_codec.h> | 36 | #include <sound/ac97_codec.h> |
36 | #include "ac97_patch.h" | 37 | #include "ac97_patch.h" |
37 | #include "ac97_id.h" | 38 | #include "ac97_id.h" |
@@ -51,6 +52,20 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro | |||
51 | return 0; | 52 | return 0; |
52 | } | 53 | } |
53 | 54 | ||
55 | /* replace with a new TLV */ | ||
56 | static void reset_tlv(struct snd_ac97 *ac97, const char *name, | ||
57 | unsigned int *tlv) | ||
58 | { | ||
59 | struct snd_ctl_elem_id sid; | ||
60 | struct snd_kcontrol *kctl; | ||
61 | memset(&sid, 0, sizeof(sid)); | ||
62 | strcpy(sid.name, name); | ||
63 | sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
64 | kctl = snd_ctl_find_id(ac97->bus->card, &sid); | ||
65 | if (kctl && kctl->tlv.p) | ||
66 | kctl->tlv.p = tlv; | ||
67 | } | ||
68 | |||
54 | /* set to the page, update bits and restore the page */ | 69 | /* set to the page, update bits and restore the page */ |
55 | static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page) | 70 | static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page) |
56 | { | 71 | { |
@@ -466,7 +481,7 @@ int patch_wolfson05(struct snd_ac97 * ac97) | |||
466 | ac97->build_ops = &patch_wolfson_wm9705_ops; | 481 | ac97->build_ops = &patch_wolfson_wm9705_ops; |
467 | #ifdef CONFIG_TOUCHSCREEN_WM9705 | 482 | #ifdef CONFIG_TOUCHSCREEN_WM9705 |
468 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ | 483 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ |
469 | ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; | 484 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; |
470 | #endif | 485 | #endif |
471 | return 0; | 486 | return 0; |
472 | } | 487 | } |
@@ -1380,6 +1395,17 @@ static void ad1888_resume(struct snd_ac97 *ac97) | |||
1380 | 1395 | ||
1381 | #endif | 1396 | #endif |
1382 | 1397 | ||
1398 | static const struct snd_ac97_res_table ad1819_restbl[] = { | ||
1399 | { AC97_PHONE, 0x9f1f }, | ||
1400 | { AC97_MIC, 0x9f1f }, | ||
1401 | { AC97_LINE, 0x9f1f }, | ||
1402 | { AC97_CD, 0x9f1f }, | ||
1403 | { AC97_VIDEO, 0x9f1f }, | ||
1404 | { AC97_AUX, 0x9f1f }, | ||
1405 | { AC97_PCM, 0x9f1f }, | ||
1406 | { } /* terminator */ | ||
1407 | }; | ||
1408 | |||
1383 | int patch_ad1819(struct snd_ac97 * ac97) | 1409 | int patch_ad1819(struct snd_ac97 * ac97) |
1384 | { | 1410 | { |
1385 | unsigned short scfg; | 1411 | unsigned short scfg; |
@@ -1387,6 +1413,7 @@ int patch_ad1819(struct snd_ac97 * ac97) | |||
1387 | // patch for Analog Devices | 1413 | // patch for Analog Devices |
1388 | scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); | 1414 | scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); |
1389 | snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */ | 1415 | snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */ |
1416 | ac97->res_table = ad1819_restbl; | ||
1390 | return 0; | 1417 | return 0; |
1391 | } | 1418 | } |
1392 | 1419 | ||
@@ -1522,12 +1549,16 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = { | |||
1522 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ | 1549 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ |
1523 | }; | 1550 | }; |
1524 | 1551 | ||
1552 | static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); | ||
1553 | |||
1525 | static int patch_ad1885_specific(struct snd_ac97 * ac97) | 1554 | static int patch_ad1885_specific(struct snd_ac97 * ac97) |
1526 | { | 1555 | { |
1527 | int err; | 1556 | int err; |
1528 | 1557 | ||
1529 | if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) | 1558 | if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) |
1530 | return err; | 1559 | return err; |
1560 | reset_tlv(ac97, "Headphone Playback Volume", | ||
1561 | db_scale_6bit_6db_max); | ||
1531 | return 0; | 1562 | return 0; |
1532 | } | 1563 | } |
1533 | 1564 | ||
@@ -1551,12 +1582,27 @@ int patch_ad1885(struct snd_ac97 * ac97) | |||
1551 | return 0; | 1582 | return 0; |
1552 | } | 1583 | } |
1553 | 1584 | ||
1585 | static int patch_ad1886_specific(struct snd_ac97 * ac97) | ||
1586 | { | ||
1587 | reset_tlv(ac97, "Headphone Playback Volume", | ||
1588 | db_scale_6bit_6db_max); | ||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | static struct snd_ac97_build_ops patch_ad1886_build_ops = { | ||
1593 | .build_specific = &patch_ad1886_specific, | ||
1594 | #ifdef CONFIG_PM | ||
1595 | .resume = ad18xx_resume | ||
1596 | #endif | ||
1597 | }; | ||
1598 | |||
1554 | int patch_ad1886(struct snd_ac97 * ac97) | 1599 | int patch_ad1886(struct snd_ac97 * ac97) |
1555 | { | 1600 | { |
1556 | patch_ad1881(ac97); | 1601 | patch_ad1881(ac97); |
1557 | /* Presario700 workaround */ | 1602 | /* Presario700 workaround */ |
1558 | /* for Jack Sense/SPDIF Register misetting causing */ | 1603 | /* for Jack Sense/SPDIF Register misetting causing */ |
1559 | snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010); | 1604 | snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010); |
1605 | ac97->build_ops = &patch_ad1886_build_ops; | ||
1560 | return 0; | 1606 | return 0; |
1561 | } | 1607 | } |
1562 | 1608 | ||
@@ -2015,6 +2061,8 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = { | |||
2015 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ | 2061 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ |
2016 | }; | 2062 | }; |
2017 | 2063 | ||
2064 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); | ||
2065 | |||
2018 | static int patch_alc650_specific(struct snd_ac97 * ac97) | 2066 | static int patch_alc650_specific(struct snd_ac97 * ac97) |
2019 | { | 2067 | { |
2020 | int err; | 2068 | int err; |
@@ -2025,6 +2073,9 @@ static int patch_alc650_specific(struct snd_ac97 * ac97) | |||
2025 | if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) | 2073 | if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) |
2026 | return err; | 2074 | return err; |
2027 | } | 2075 | } |
2076 | if (ac97->id != AC97_ID_ALC650F) | ||
2077 | reset_tlv(ac97, "Master Playback Volume", | ||
2078 | db_scale_5bit_3db_max); | ||
2028 | return 0; | 2079 | return 0; |
2029 | } | 2080 | } |
2030 | 2081 | ||
@@ -2208,7 +2259,8 @@ int patch_alc655(struct snd_ac97 * ac97) | |||
2208 | val &= ~(1 << 1); /* Pin 47 is spdif input pin */ | 2259 | val &= ~(1 << 1); /* Pin 47 is spdif input pin */ |
2209 | else { /* ALC655 */ | 2260 | else { /* ALC655 */ |
2210 | if (ac97->subsystem_vendor == 0x1462 && | 2261 | if (ac97->subsystem_vendor == 0x1462 && |
2211 | ac97->subsystem_device == 0x0131) /* MSI S270 laptop */ | 2262 | (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */ |
2263 | ac97->subsystem_device == 0x0161)) /* LG K1 Express */ | ||
2212 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ | 2264 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ |
2213 | else | 2265 | else |
2214 | val |= (1 << 1); /* Pin 47 is spdif input pin */ | 2266 | val |= (1 << 1); /* Pin 47 is spdif input pin */ |
@@ -2759,6 +2811,10 @@ int patch_vt1616(struct snd_ac97 * ac97) | |||
2759 | */ | 2811 | */ |
2760 | int patch_vt1617a(struct snd_ac97 * ac97) | 2812 | int patch_vt1617a(struct snd_ac97 * ac97) |
2761 | { | 2813 | { |
2814 | /* bring analog power consumption to normal, like WinXP driver | ||
2815 | * for EPIA SP | ||
2816 | */ | ||
2817 | snd_ac97_write_cache(ac97, 0x5c, 0x20); | ||
2762 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ | 2818 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
2763 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; | 2819 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; |
2764 | return 0; | 2820 | return 0; |
@@ -2872,3 +2928,41 @@ int patch_lm4550(struct snd_ac97 *ac97) | |||
2872 | ac97->res_table = lm4550_restbl; | 2928 | ac97->res_table = lm4550_restbl; |
2873 | return 0; | 2929 | return 0; |
2874 | } | 2930 | } |
2931 | |||
2932 | /* | ||
2933 | * UCB1400 codec (http://www.semiconductors.philips.com/acrobat_download/datasheets/UCB1400-02.pdf) | ||
2934 | */ | ||
2935 | static const struct snd_kcontrol_new snd_ac97_controls_ucb1400[] = { | ||
2936 | /* enable/disable headphone driver which allows direct connection to | ||
2937 | stereo headphone without the use of external DC blocking | ||
2938 | capacitors */ | ||
2939 | AC97_SINGLE("Headphone Driver", 0x6a, 6, 1, 0), | ||
2940 | /* Filter used to compensate the DC offset is added in the ADC to remove idle | ||
2941 | tones from the audio band. */ | ||
2942 | AC97_SINGLE("DC Filter", 0x6a, 4, 1, 0), | ||
2943 | /* Control smart-low-power mode feature. Allows automatic power down | ||
2944 | of unused blocks in the ADC analog front end and the PLL. */ | ||
2945 | AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0), | ||
2946 | }; | ||
2947 | |||
2948 | static int patch_ucb1400_specific(struct snd_ac97 * ac97) | ||
2949 | { | ||
2950 | int idx, err; | ||
2951 | for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++) | ||
2952 | if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0) | ||
2953 | return err; | ||
2954 | return 0; | ||
2955 | } | ||
2956 | |||
2957 | static struct snd_ac97_build_ops patch_ucb1400_ops = { | ||
2958 | .build_specific = patch_ucb1400_specific, | ||
2959 | }; | ||
2960 | |||
2961 | int patch_ucb1400(struct snd_ac97 * ac97) | ||
2962 | { | ||
2963 | ac97->build_ops = &patch_ucb1400_ops; | ||
2964 | /* enable headphone driver and smart low power mode by default */ | ||
2965 | snd_ac97_write(ac97, 0x6a, 0x0050); | ||
2966 | snd_ac97_write(ac97, 0x6c, 0x0030); | ||
2967 | return 0; | ||
2968 | } | ||
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index adcaa04586cb..741979217207 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -58,5 +58,6 @@ int patch_cm9780(struct snd_ac97 * ac97); | |||
58 | int patch_vt1616(struct snd_ac97 * ac97); | 58 | int patch_vt1616(struct snd_ac97 * ac97); |
59 | int patch_vt1617a(struct snd_ac97 * ac97); | 59 | int patch_vt1617a(struct snd_ac97 * ac97); |
60 | int patch_it2646(struct snd_ac97 * ac97); | 60 | int patch_it2646(struct snd_ac97 * ac97); |
61 | int patch_ucb1400(struct snd_ac97 * ac97); | ||
61 | int mpatch_si3036(struct snd_ac97 * ac97); | 62 | int mpatch_si3036(struct snd_ac97 * ac97); |
62 | int patch_lm4550(struct snd_ac97 * ac97); | 63 | int patch_lm4550(struct snd_ac97 * ac97); |
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index f684aa2c0067..3758d07182f8 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c | |||
@@ -269,6 +269,7 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate) | |||
269 | return -EINVAL; | 269 | return -EINVAL; |
270 | } | 270 | } |
271 | 271 | ||
272 | snd_ac97_update_power(ac97, reg, 1); | ||
272 | switch (reg) { | 273 | switch (reg) { |
273 | case AC97_PCM_MIC_ADC_RATE: | 274 | case AC97_PCM_MIC_ADC_RATE: |
274 | if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ | 275 | if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ |
@@ -606,6 +607,7 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, | |||
606 | goto error; | 607 | goto error; |
607 | } | 608 | } |
608 | } | 609 | } |
610 | pcm->cur_dbl = r; | ||
609 | spin_unlock_irq(&pcm->bus->bus_lock); | 611 | spin_unlock_irq(&pcm->bus->bus_lock); |
610 | for (i = 3; i < 12; i++) { | 612 | for (i = 3; i < 12; i++) { |
611 | if (!(slots & (1 << i))) | 613 | if (!(slots & (1 << i))) |
@@ -651,6 +653,21 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) | |||
651 | unsigned short slots = pcm->aslots; | 653 | unsigned short slots = pcm->aslots; |
652 | int i, cidx; | 654 | int i, cidx; |
653 | 655 | ||
656 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
657 | int r = pcm->cur_dbl; | ||
658 | for (i = 3; i < 12; i++) { | ||
659 | if (!(slots & (1 << i))) | ||
660 | continue; | ||
661 | for (cidx = 0; cidx < 4; cidx++) { | ||
662 | if (pcm->r[r].rslots[cidx] & (1 << i)) { | ||
663 | int reg = get_slot_reg(pcm, cidx, i, r); | ||
664 | snd_ac97_update_power(pcm->r[r].codec[cidx], | ||
665 | reg, 0); | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | #endif | ||
670 | |||
654 | bus = pcm->bus; | 671 | bus = pcm->bus; |
655 | spin_lock_irq(&pcm->bus->bus_lock); | 672 | spin_lock_irq(&pcm->bus->bus_lock); |
656 | for (i = 3; i < 12; i++) { | 673 | for (i = 3; i < 12; i++) { |
@@ -660,6 +677,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) | |||
660 | bus->used_slots[pcm->stream][cidx] &= ~(1 << i); | 677 | bus->used_slots[pcm->stream][cidx] &= ~(1 << i); |
661 | } | 678 | } |
662 | pcm->aslots = 0; | 679 | pcm->aslots = 0; |
680 | pcm->cur_dbl = 0; | ||
663 | spin_unlock_irq(&pcm->bus->bus_lock); | 681 | spin_unlock_irq(&pcm->bus->bus_lock); |
664 | return 0; | 682 | return 0; |
665 | } | 683 | } |
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 2118df50b9d6..a3fdd7da911c 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c | |||
@@ -457,14 +457,10 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) | |||
457 | 457 | ||
458 | void snd_ac97_proc_done(struct snd_ac97 * ac97) | 458 | void snd_ac97_proc_done(struct snd_ac97 * ac97) |
459 | { | 459 | { |
460 | if (ac97->proc_regs) { | 460 | snd_info_free_entry(ac97->proc_regs); |
461 | snd_info_unregister(ac97->proc_regs); | 461 | ac97->proc_regs = NULL; |
462 | ac97->proc_regs = NULL; | 462 | snd_info_free_entry(ac97->proc); |
463 | } | 463 | ac97->proc = NULL; |
464 | if (ac97->proc) { | ||
465 | snd_info_unregister(ac97->proc); | ||
466 | ac97->proc = NULL; | ||
467 | } | ||
468 | } | 464 | } |
469 | 465 | ||
470 | void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) | 466 | void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) |
@@ -485,8 +481,6 @@ void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) | |||
485 | 481 | ||
486 | void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus) | 482 | void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus) |
487 | { | 483 | { |
488 | if (bus->proc) { | 484 | snd_info_free_entry(bus->proc); |
489 | snd_info_unregister(bus->proc); | 485 | bus->proc = NULL; |
490 | bus->proc = NULL; | ||
491 | } | ||
492 | } | 486 | } |
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index 94c26ec05882..c153cb79c518 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <sound/core.h> | 28 | #include <sound/core.h> |
29 | #include <sound/ak4531_codec.h> | 29 | #include <sound/ak4531_codec.h> |
30 | #include <sound/tlv.h> | ||
30 | 31 | ||
31 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | 32 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); |
32 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); | 33 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); |
@@ -63,6 +64,14 @@ static void snd_ak4531_dump(struct snd_ak4531 *ak4531) | |||
63 | .info = snd_ak4531_info_single, \ | 64 | .info = snd_ak4531_info_single, \ |
64 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ | 65 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ |
65 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) } | 66 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) } |
67 | #define AK4531_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
68 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
69 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
70 | .name = xname, .index = xindex, \ | ||
71 | .info = snd_ak4531_info_single, \ | ||
72 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ | ||
73 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22), \ | ||
74 | .tlv = { .p = (xtlv) } } | ||
66 | 75 | ||
67 | static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 76 | static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
68 | { | 77 | { |
@@ -122,6 +131,14 @@ static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
122 | .info = snd_ak4531_info_double, \ | 131 | .info = snd_ak4531_info_double, \ |
123 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ | 132 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ |
124 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) } | 133 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) } |
134 | #define AK4531_DOUBLE_TLV(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert, xtlv) \ | ||
135 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
136 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
137 | .name = xname, .index = xindex, \ | ||
138 | .info = snd_ak4531_info_double, \ | ||
139 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ | ||
140 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22), \ | ||
141 | .tlv = { .p = (xtlv) } } | ||
125 | 142 | ||
126 | static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 143 | static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
127 | { | 144 | { |
@@ -250,50 +267,62 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
250 | return change; | 267 | return change; |
251 | } | 268 | } |
252 | 269 | ||
270 | static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); | ||
271 | static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); | ||
272 | static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); | ||
273 | |||
253 | static struct snd_kcontrol_new snd_ak4531_controls[] = { | 274 | static struct snd_kcontrol_new snd_ak4531_controls[] = { |
254 | 275 | ||
255 | AK4531_DOUBLE("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1), | 276 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, |
277 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, | ||
278 | db_scale_master), | ||
256 | AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), | 279 | AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), |
257 | 280 | ||
258 | AK4531_SINGLE("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1), | 281 | AK4531_SINGLE_TLV("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1, |
282 | db_scale_mono), | ||
259 | AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), | 283 | AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), |
260 | 284 | ||
261 | AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), | 285 | AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), |
262 | AK4531_DOUBLE("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1), | 286 | AK4531_DOUBLE_TLV("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1, |
287 | db_scale_input), | ||
263 | AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), | 288 | AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), |
264 | AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), | 289 | AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), |
265 | 290 | ||
266 | AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), | 291 | AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), |
267 | AK4531_DOUBLE("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1), | 292 | AK4531_DOUBLE_TLV("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1, |
293 | db_scale_input), | ||
268 | AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), | 294 | AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), |
269 | AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), | 295 | AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), |
270 | 296 | ||
271 | AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), | 297 | AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), |
272 | AK4531_DOUBLE("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1), | 298 | AK4531_DOUBLE_TLV("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1, |
299 | db_scale_input), | ||
273 | AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), | 300 | AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), |
274 | AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), | 301 | AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), |
275 | 302 | ||
276 | AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), | 303 | AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), |
277 | AK4531_DOUBLE("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1), | 304 | AK4531_DOUBLE_TLV("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1, |
305 | db_scale_input), | ||
278 | AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), | 306 | AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), |
279 | AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), | 307 | AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), |
280 | 308 | ||
281 | AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), | 309 | AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), |
282 | AK4531_DOUBLE("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1), | 310 | AK4531_DOUBLE_TLV("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1, |
311 | db_scale_input), | ||
283 | AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), | 312 | AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), |
284 | AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), | 313 | AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), |
285 | 314 | ||
286 | AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), | 315 | AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), |
287 | AK4531_SINGLE("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1), | 316 | AK4531_SINGLE_TLV("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1, db_scale_input), |
288 | AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), | 317 | AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), |
289 | AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), | 318 | AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), |
290 | 319 | ||
291 | AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), | 320 | AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), |
292 | AK4531_SINGLE("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1), | 321 | AK4531_SINGLE_TLV("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1, db_scale_input), |
293 | AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), | 322 | AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), |
294 | AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), | 323 | AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), |
295 | 324 | ||
296 | AK4531_SINGLE("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1), | 325 | AK4531_SINGLE_TLV("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1, db_scale_input), |
297 | AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), | 326 | AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), |
298 | AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), | 327 | AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), |
299 | AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), | 328 | AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), |