aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-06-27 12:28:53 -0400
committerJaroslav Kysela <perex@suse.cz>2006-09-23 04:37:08 -0400
commit6dbe662874ba08585eaf732d126762c25ac8e3f7 (patch)
tree7460c36d4d848f223b682f7a700866bcf6dbc7d5
parent2b29b13c5794f648cd5e839796496704d787f5a6 (diff)
[ALSA] Add experimental support of aggressive AC97 power-saving mode
Added CONFIG_SND_AC97_POWER_SAVE kernel config to enable the support of aggressive AC97 power-saving mode. In this mode, the AC97 powerdown register bits are dynamically controlled at each open/close of PCM streams. The mode is activated via power_save option for snd-ac97-codec driver. As default it's off. It can be turned on/off on the fly via sysfs, too. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
-rw-r--r--include/sound/ac97_codec.h32
-rw-r--r--sound/drivers/Kconfig13
-rw-r--r--sound/pci/ac97/ac97_codec.c264
-rw-r--r--sound/pci/ac97/ac97_pcm.c18
-rw-r--r--sound/pci/intel8x0.c14
-rw-r--r--sound/pci/via82xx.c13
6 files changed, 315 insertions, 39 deletions
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 758f8bf133c7..4c43521cc493 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -27,6 +27,7 @@
27 27
28#include <linux/bitops.h> 28#include <linux/bitops.h>
29#include <linux/device.h> 29#include <linux/device.h>
30#include <linux/workqueue.h>
30#include "pcm.h" 31#include "pcm.h"
31#include "control.h" 32#include "control.h"
32#include "info.h" 33#include "info.h"
@@ -140,6 +141,20 @@
140#define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */ 141#define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */
141#define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */ 142#define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */
142 143
144/* powerdown bits */
145#define AC97_PD_ADC_STATUS 0x0001 /* ADC status (RO) */
146#define AC97_PD_DAC_STATUS 0x0002 /* DAC status (RO) */
147#define AC97_PD_MIXER_STATUS 0x0004 /* Analog mixer status (RO) */
148#define AC97_PD_VREF_STATUS 0x0008 /* Vref status (RO) */
149#define AC97_PD_PR0 0x0100 /* Power down PCM ADCs and input MUX */
150#define AC97_PD_PR1 0x0200 /* Power down PCM front DAC */
151#define AC97_PD_PR2 0x0400 /* Power down Mixer (Vref still on) */
152#define AC97_PD_PR3 0x0800 /* Power down Mixer (Vref off) */
153#define AC97_PD_PR4 0x1000 /* Power down AC-Link */
154#define AC97_PD_PR5 0x2000 /* Disable internal clock usage */
155#define AC97_PD_PR6 0x4000 /* Headphone amplifier */
156#define AC97_PD_EAPD 0x8000 /* External Amplifer Power Down (EAPD) */
157
143/* extended audio ID bit defines */ 158/* extended audio ID bit defines */
144#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */ 159#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
145#define AC97_EI_DRA 0x0002 /* Double rate supported */ 160#define AC97_EI_DRA 0x0002 /* Double rate supported */
@@ -359,6 +374,7 @@
359#define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */ 374#define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */
360#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */ 375#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
361#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */ 376#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
377#define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */
362 378
363/* ac97->flags */ 379/* ac97->flags */
364#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ 380#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
@@ -491,6 +507,12 @@ struct snd_ac97 {
491 /* jack-sharing info */ 507 /* jack-sharing info */
492 unsigned char indep_surround; 508 unsigned char indep_surround;
493 unsigned char channel_mode; 509 unsigned char channel_mode;
510
511#ifdef CONFIG_SND_AC97_POWER_SAVE
512 unsigned int power_up; /* power states */
513 struct workqueue_struct *power_workq;
514 struct work_struct power_work;
515#endif
494 struct device dev; 516 struct device dev;
495}; 517};
496 518
@@ -532,6 +554,15 @@ unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
532void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value); 554void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
533int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value); 555int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
534int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value); 556int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value);
557#ifdef CONFIG_SND_AC97_POWER_SAVE
558int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup);
559#else
560static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg,
561 int powerup)
562{
563 return 0;
564}
565#endif
535#ifdef CONFIG_PM 566#ifdef CONFIG_PM
536void snd_ac97_suspend(struct snd_ac97 *ac97); 567void snd_ac97_suspend(struct snd_ac97 *ac97);
537void snd_ac97_resume(struct snd_ac97 *ac97); 568void snd_ac97_resume(struct snd_ac97 *ac97);
@@ -583,6 +614,7 @@ struct ac97_pcm {
583 copy_flag: 1, /* lowlevel driver must fill all entries */ 614 copy_flag: 1, /* lowlevel driver must fill all entries */
584 spdif: 1; /* spdif pcm */ 615 spdif: 1; /* spdif pcm */
585 unsigned short aslots; /* active slots */ 616 unsigned short aslots; /* active slots */
617 unsigned short cur_dbl; /* current double-rate state */
586 unsigned int rates; /* available rates */ 618 unsigned int rates; /* available rates */
587 struct { 619 struct {
588 unsigned short slots; /* driver input: requested AC97 slot numbers */ 620 unsigned short slots; /* driver input: requested AC97 slot numbers */
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 395c4ef52ac9..897dc2dfd7dd 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -100,4 +100,17 @@ config SND_MPU401
100 To compile this driver as a module, choose M here: the module 100 To compile this driver as a module, choose M here: the module
101 will be called snd-mpu401. 101 will be called snd-mpu401.
102 102
103config SND_AC97_POWER_SAVE
104 bool "AC97 Power-Saving Mode"
105 depends on SND_AC97_CODEC && EXPERIMENTAL
106 default n
107 help
108 Say Y here to enable the aggressive power-saving support of
109 AC97 codecs. In this mode, the power-mode is dynamically
110 controlled at each open/close.
111
112 The mode is activated by passing power_save=1 option to
113 snd-ac97-codec driver. You can toggle it dynamically over
114 sysfs, too.
115
103endmenu 116endmenu
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index b35280ca2465..f82c636e99a9 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -47,6 +47,11 @@ static int enable_loopback;
47module_param(enable_loopback, bool, 0444); 47module_param(enable_loopback, bool, 0444);
48MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); 48MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
49 49
50#ifdef CONFIG_SND_AC97_POWER_SAVE
51static int power_save;
52module_param(power_save, bool, 0644);
53MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control");
54#endif
50/* 55/*
51 56
52 */ 57 */
@@ -187,6 +192,8 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
187}; 192};
188 193
189 194
195static void update_power_regs(struct snd_ac97 *ac97);
196
190/* 197/*
191 * I/O routines 198 * I/O routines
192 */ 199 */
@@ -554,6 +561,18 @@ int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
554 } 561 }
555 err = snd_ac97_update_bits(ac97, reg, val_mask, val); 562 err = snd_ac97_update_bits(ac97, reg, val_mask, val);
556 snd_ac97_page_restore(ac97, page_save); 563 snd_ac97_page_restore(ac97, page_save);
564#ifdef CONFIG_SND_AC97_POWER_SAVE
565 /* check analog mixer power-down */
566 if ((val_mask & 0x8000) &&
567 (kcontrol->private_value & (1<<30))) {
568 if (val & 0x8000)
569 ac97->power_up &= ~(1 << (reg>>1));
570 else
571 ac97->power_up |= 1 << (reg>>1);
572 if (power_save)
573 update_power_regs(ac97);
574 }
575#endif
557 return err; 576 return err;
558} 577}
559 578
@@ -962,6 +981,10 @@ static int snd_ac97_bus_dev_free(struct snd_device *device)
962static int snd_ac97_free(struct snd_ac97 *ac97) 981static int snd_ac97_free(struct snd_ac97 *ac97)
963{ 982{
964 if (ac97) { 983 if (ac97) {
984#ifdef CONFIG_SND_AC97_POWER_SAVE
985 if (ac97->power_workq)
986 destroy_workqueue(ac97->power_workq);
987#endif
965 snd_ac97_proc_done(ac97); 988 snd_ac97_proc_done(ac97);
966 if (ac97->bus) 989 if (ac97->bus)
967 ac97->bus->codec[ac97->num] = NULL; 990 ac97->bus->codec[ac97->num] = NULL;
@@ -1117,7 +1140,9 @@ struct snd_kcontrol *snd_ac97_cnew(const struct snd_kcontrol_new *_template, str
1117/* 1140/*
1118 * create mute switch(es) for normal stereo controls 1141 * create mute switch(es) for normal stereo controls
1119 */ 1142 */
1120static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, int check_stereo, struct snd_ac97 *ac97) 1143static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
1144 int check_stereo, int check_amix,
1145 struct snd_ac97 *ac97)
1121{ 1146{
1122 struct snd_kcontrol *kctl; 1147 struct snd_kcontrol *kctl;
1123 int err; 1148 int err;
@@ -1137,10 +1162,14 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
1137 } 1162 }
1138 if (mute_mask == 0x8080) { 1163 if (mute_mask == 0x8080) {
1139 struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); 1164 struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
1165 if (check_amix)
1166 tmp.private_value |= (1 << 30);
1140 tmp.index = ac97->num; 1167 tmp.index = ac97->num;
1141 kctl = snd_ctl_new1(&tmp, ac97); 1168 kctl = snd_ctl_new1(&tmp, ac97);
1142 } else { 1169 } else {
1143 struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); 1170 struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1);
1171 if (check_amix)
1172 tmp.private_value |= (1 << 30);
1144 tmp.index = ac97->num; 1173 tmp.index = ac97->num;
1145 kctl = snd_ctl_new1(&tmp, ac97); 1174 kctl = snd_ctl_new1(&tmp, ac97);
1146 } 1175 }
@@ -1186,7 +1215,9 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne
1186/* 1215/*
1187 * create a mute-switch and a volume for normal stereo/mono controls 1216 * create a mute-switch and a volume for normal stereo/mono controls
1188 */ 1217 */
1189static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, struct snd_ac97 *ac97) 1218static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx,
1219 int reg, int check_stereo, int check_amix,
1220 struct snd_ac97 *ac97)
1190{ 1221{
1191 int err; 1222 int err;
1192 char name[44]; 1223 char name[44];
@@ -1197,7 +1228,9 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int
1197 1228
1198 if (snd_ac97_try_bit(ac97, reg, 15)) { 1229 if (snd_ac97_try_bit(ac97, reg, 15)) {
1199 sprintf(name, "%s Switch", pfx); 1230 sprintf(name, "%s Switch", pfx);
1200 if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0) 1231 if ((err = snd_ac97_cmute_new_stereo(card, name, reg,
1232 check_stereo, check_amix,
1233 ac97)) < 0)
1201 return err; 1234 return err;
1202 } 1235 }
1203 check_volume_resolution(ac97, reg, &lo_max, &hi_max); 1236 check_volume_resolution(ac97, reg, &lo_max, &hi_max);
@@ -1209,8 +1242,10 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int
1209 return 0; 1242 return 0;
1210} 1243}
1211 1244
1212#define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97) 1245#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) 1246 snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97)
1247#define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \
1248 snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97)
1214 1249
1215static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97); 1250static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);
1216 1251
@@ -1226,9 +1261,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 */ 1261 /* 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)) { 1262 if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
1228 if (ac97->flags & AC97_HAS_NO_MASTER_VOL) 1263 if (ac97->flags & AC97_HAS_NO_MASTER_VOL)
1229 err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, ac97); 1264 err = snd_ac97_cmute_new(card, "Master Playback Switch",
1265 AC97_MASTER, 0, ac97);
1230 else 1266 else
1231 err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97); 1267 err = snd_ac97_cmix_new(card, "Master Playback",
1268 AC97_MASTER, 0, ac97);
1232 if (err < 0) 1269 if (err < 0)
1233 return err; 1270 return err;
1234 } 1271 }
@@ -1265,19 +1302,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
1265 if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) 1302 if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER))
1266 && !(ac97->flags & AC97_AD_MULTI)) { 1303 && !(ac97->flags & AC97_AD_MULTI)) {
1267 /* Surround Master (0x38) is with stereo mutes */ 1304 /* Surround Master (0x38) is with stereo mutes */
1268 if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0) 1305 if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback",
1306 AC97_SURROUND_MASTER, 1, 0,
1307 ac97)) < 0)
1269 return err; 1308 return err;
1270 } 1309 }
1271 1310
1272 /* build headphone controls */ 1311 /* build headphone controls */
1273 if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { 1312 if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
1274 if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0) 1313 if ((err = snd_ac97_cmix_new(card, "Headphone Playback",
1314 AC97_HEADPHONE, 0, ac97)) < 0)
1275 return err; 1315 return err;
1276 } 1316 }
1277 1317
1278 /* build master mono controls */ 1318 /* build master mono controls */
1279 if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { 1319 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) 1320 if ((err = snd_ac97_cmix_new(card, "Master Mono Playback",
1321 AC97_MASTER_MONO, 0, ac97)) < 0)
1281 return err; 1322 return err;
1282 } 1323 }
1283 1324
@@ -1310,7 +1351,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
1310 /* build Phone controls */ 1351 /* build Phone controls */
1311 if (!(ac97->flags & AC97_HAS_NO_PHONE)) { 1352 if (!(ac97->flags & AC97_HAS_NO_PHONE)) {
1312 if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { 1353 if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
1313 if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0) 1354 if ((err = snd_ac97_cmix_new(card, "Phone Playback",
1355 AC97_PHONE, 1, ac97)) < 0)
1314 return err; 1356 return err;
1315 } 1357 }
1316 } 1358 }
@@ -1318,7 +1360,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
1318 /* build MIC controls */ 1360 /* build MIC controls */
1319 if (!(ac97->flags & AC97_HAS_NO_MIC)) { 1361 if (!(ac97->flags & AC97_HAS_NO_MIC)) {
1320 if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { 1362 if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
1321 if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0) 1363 if ((err = snd_ac97_cmix_new(card, "Mic Playback",
1364 AC97_MIC, 1, ac97)) < 0)
1322 return err; 1365 return err;
1323 if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) 1366 if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
1324 return err; 1367 return err;
@@ -1327,14 +1370,16 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
1327 1370
1328 /* build Line controls */ 1371 /* build Line controls */
1329 if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { 1372 if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) {
1330 if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0) 1373 if ((err = snd_ac97_cmix_new(card, "Line Playback",
1374 AC97_LINE, 1, ac97)) < 0)
1331 return err; 1375 return err;
1332 } 1376 }
1333 1377
1334 /* build CD controls */ 1378 /* build CD controls */
1335 if (!(ac97->flags & AC97_HAS_NO_CD)) { 1379 if (!(ac97->flags & AC97_HAS_NO_CD)) {
1336 if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { 1380 if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
1337 if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0) 1381 if ((err = snd_ac97_cmix_new(card, "CD Playback",
1382 AC97_CD, 1, ac97)) < 0)
1338 return err; 1383 return err;
1339 } 1384 }
1340 } 1385 }
@@ -1342,7 +1387,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
1342 /* build Video controls */ 1387 /* build Video controls */
1343 if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { 1388 if (!(ac97->flags & AC97_HAS_NO_VIDEO)) {
1344 if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { 1389 if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
1345 if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0) 1390 if ((err = snd_ac97_cmix_new(card, "Video Playback",
1391 AC97_VIDEO, 1, ac97)) < 0)
1346 return err; 1392 return err;
1347 } 1393 }
1348 } 1394 }
@@ -1350,7 +1396,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
1350 /* build Aux controls */ 1396 /* build Aux controls */
1351 if (!(ac97->flags & AC97_HAS_NO_AUX)) { 1397 if (!(ac97->flags & AC97_HAS_NO_AUX)) {
1352 if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { 1398 if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
1353 if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) 1399 if ((err = snd_ac97_cmix_new(card, "Aux Playback",
1400 AC97_AUX, 1, ac97)) < 0)
1354 return err; 1401 return err;
1355 } 1402 }
1356 } 1403 }
@@ -1385,9 +1432,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
1385 } else { 1432 } else {
1386 if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { 1433 if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
1387 if (ac97->flags & AC97_HAS_NO_PCM_VOL) 1434 if (ac97->flags & AC97_HAS_NO_PCM_VOL)
1388 err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97); 1435 err = snd_ac97_cmute_new(card,
1436 "PCM Playback Switch",
1437 AC97_PCM, 0, ac97);
1389 else 1438 else
1390 err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97); 1439 err = snd_ac97_cmix_new(card, "PCM Playback",
1440 AC97_PCM, 0, ac97);
1391 if (err < 0) 1441 if (err < 0)
1392 return err; 1442 return err;
1393 } 1443 }
@@ -1398,7 +1448,9 @@ 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) 1448 if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
1399 return err; 1449 return err;
1400 if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { 1450 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) 1451 err = snd_ac97_cmute_new(card, "Capture Switch",
1452 AC97_REC_GAIN, 0, ac97);
1453 if (err < 0)
1402 return err; 1454 return err;
1403 } 1455 }
1404 if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) 1456 if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
@@ -1829,6 +1881,13 @@ static int snd_ac97_dev_disconnect(struct snd_device *device)
1829/* build_ops to do nothing */ 1881/* build_ops to do nothing */
1830static struct snd_ac97_build_ops null_build_ops; 1882static struct snd_ac97_build_ops null_build_ops;
1831 1883
1884#ifdef CONFIG_SND_AC97_POWER_SAVE
1885static void do_update_power(void *data)
1886{
1887 update_power_regs(data);
1888}
1889#endif
1890
1832/** 1891/**
1833 * snd_ac97_mixer - create an Codec97 component 1892 * snd_ac97_mixer - create an Codec97 component
1834 * @bus: the AC97 bus which codec is attached to 1893 * @bus: the AC97 bus which codec is attached to
@@ -1883,6 +1942,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
1883 bus->codec[ac97->num] = ac97; 1942 bus->codec[ac97->num] = ac97;
1884 mutex_init(&ac97->reg_mutex); 1943 mutex_init(&ac97->reg_mutex);
1885 mutex_init(&ac97->page_mutex); 1944 mutex_init(&ac97->page_mutex);
1945#ifdef CONFIG_SND_AC97_POWER_SAVE
1946 ac97->power_workq = create_workqueue("ac97");
1947 INIT_WORK(&ac97->power_work, do_update_power, ac97);
1948#endif
1886 1949
1887#ifdef CONFIG_PCI 1950#ifdef CONFIG_PCI
1888 if (ac97->pci) { 1951 if (ac97->pci) {
@@ -2117,15 +2180,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
2117 return -ENOMEM; 2180 return -ENOMEM;
2118 } 2181 }
2119 } 2182 }
2120 /* make sure the proper powerdown bits are cleared */ 2183 if (ac97_is_audio(ac97))
2121 if (ac97->scaps && ac97_is_audio(ac97)) { 2184 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); 2185 snd_ac97_proc_init(ac97);
2130 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { 2186 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) {
2131 snd_ac97_free(ac97); 2187 snd_ac97_free(ac97);
@@ -2153,22 +2209,155 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
2153 snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f); 2209 snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f);
2154 } 2210 }
2155 2211
2156 power = ac97->regs[AC97_POWERDOWN] | 0x8000; /* EAPD */ 2212 /* surround, CLFE, mic powerdown */
2157 power |= 0x4000; /* Headphone amplifier powerdown */ 2213 power = ac97->regs[AC97_EXTENDED_STATUS];
2158 power |= 0x0300; /* ADC & DAC powerdown */ 2214 if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
2215 power |= AC97_EA_PRJ;
2216 if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
2217 power |= AC97_EA_PRI | AC97_EA_PRK;
2218 power |= AC97_EA_PRL;
2219 snd_ac97_write(ac97, AC97_EXTENDED_STATUS, power);
2220
2221 /* powerdown external amplifier */
2222 if (ac97->scaps & AC97_SCAP_INV_EAPD)
2223 power = ac97->regs[AC97_POWERDOWN] & ~AC97_PD_EAPD;
2224 else if (! (ac97->scaps & AC97_SCAP_EAPD_LED))
2225 power = ac97->regs[AC97_POWERDOWN] | AC97_PD_EAPD;
2226 power |= AC97_PD_PR6; /* Headphone amplifier powerdown */
2227 power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */
2159 snd_ac97_write(ac97, AC97_POWERDOWN, power); 2228 snd_ac97_write(ac97, AC97_POWERDOWN, power);
2160 udelay(100); 2229 udelay(100);
2161 power |= 0x0400; /* Analog Mixer powerdown (Vref on) */ 2230 power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
2162 snd_ac97_write(ac97, AC97_POWERDOWN, power);
2163 udelay(100);
2164#if 0
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); 2231 snd_ac97_write(ac97, AC97_POWERDOWN, power);
2232#ifdef CONFIG_SND_AC97_POWER_SAVE
2233 if (power_save) {
2234 udelay(100);
2235 /* AC-link powerdown, internal Clk disable */
2236 /* FIXME: this may cause click noises on some boards */
2237 power |= AC97_PD_PR4 | AC97_PD_PR5;
2238 snd_ac97_write(ac97, AC97_POWERDOWN, power);
2239 }
2168#endif 2240#endif
2169} 2241}
2170 2242
2171 2243
2244struct ac97_power_reg {
2245 unsigned short reg;
2246 unsigned short power_reg;
2247 unsigned short mask;
2248};
2249
2250enum { PWIDX_ADC, PWIDX_FRONT, PWIDX_CLFE, PWIDX_SURR, PWIDX_MIC, PWIDX_SIZE };
2251
2252static struct ac97_power_reg power_regs[PWIDX_SIZE] = {
2253 [PWIDX_ADC] = { AC97_PCM_LR_ADC_RATE, AC97_POWERDOWN, AC97_PD_PR0},
2254 [PWIDX_FRONT] = { AC97_PCM_FRONT_DAC_RATE, AC97_POWERDOWN, AC97_PD_PR1},
2255 [PWIDX_CLFE] = { AC97_PCM_LFE_DAC_RATE, AC97_EXTENDED_STATUS,
2256 AC97_EA_PRI | AC97_EA_PRK},
2257 [PWIDX_SURR] = { AC97_PCM_SURR_DAC_RATE, AC97_EXTENDED_STATUS,
2258 AC97_EA_PRJ},
2259 [PWIDX_MIC] = { AC97_PCM_MIC_ADC_RATE, AC97_EXTENDED_STATUS,
2260 AC97_EA_PRL},
2261};
2262
2263#ifdef CONFIG_SND_AC97_POWER_SAVE
2264/**
2265 * snd_ac97_update_power - update the powerdown register
2266 * @ac97: the codec instance
2267 * @reg: the rate register, e.g. AC97_PCM_FRONT_DAC_RATE
2268 * @powerup: non-zero when power up the part
2269 *
2270 * Update the AC97 powerdown register bits of the given part.
2271 */
2272int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
2273{
2274 int i;
2275
2276 if (! ac97)
2277 return 0;
2278
2279 if (reg) {
2280 /* SPDIF requires DAC power, too */
2281 if (reg == AC97_SPDIF)
2282 reg = AC97_PCM_FRONT_DAC_RATE;
2283 for (i = 0; i < PWIDX_SIZE; i++) {
2284 if (power_regs[i].reg == reg) {
2285 if (powerup)
2286 ac97->power_up |= (1 << i);
2287 else
2288 ac97->power_up &= ~(1 << i);
2289 break;
2290 }
2291 }
2292 }
2293
2294 if (! power_save)
2295 return 0;
2296
2297 if (! powerup && ac97->power_workq)
2298 /* adjust power-down bits after two seconds delay
2299 * (for avoiding loud click noises for many (OSS) apps
2300 * that open/close frequently)
2301 */
2302 queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
2303 else
2304 update_power_regs(ac97);
2305
2306 return 0;
2307}
2308
2309EXPORT_SYMBOL(snd_ac97_update_power);
2310#endif /* CONFIG_SND_AC97_POWER_SAVE */
2311
2312static void update_power_regs(struct snd_ac97 *ac97)
2313{
2314 unsigned int power_up, bits;
2315 int i;
2316
2317#ifdef CONFIG_SND_AC97_POWER_SAVE
2318 if (power_save)
2319 power_up = ac97->power_up;
2320 else {
2321#endif
2322 power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
2323 power_up |= (1 << PWIDX_MIC);
2324 if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
2325 power_up |= (1 << PWIDX_SURR);
2326 if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
2327 power_up |= (1 << PWIDX_CLFE);
2328#ifdef CONFIG_SND_AC97_POWER_SAVE
2329 }
2330#endif
2331 if (power_up) {
2332 if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
2333 /* needs power-up analog mix and vref */
2334 snd_ac97_update_bits(ac97, AC97_POWERDOWN,
2335 AC97_PD_PR3, 0);
2336 msleep(1);
2337 snd_ac97_update_bits(ac97, AC97_POWERDOWN,
2338 AC97_PD_PR2, 0);
2339 }
2340 }
2341 for (i = 0; i < PWIDX_SIZE; i++) {
2342 if (power_up & (1 << i))
2343 bits = 0;
2344 else
2345 bits = power_regs[i].mask;
2346 snd_ac97_update_bits(ac97, power_regs[i].power_reg,
2347 power_regs[i].mask, bits);
2348 }
2349 if (! power_up) {
2350 if (! (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2)) {
2351 /* power down analog mix and vref */
2352 snd_ac97_update_bits(ac97, AC97_POWERDOWN,
2353 AC97_PD_PR2, AC97_PD_PR2);
2354 snd_ac97_update_bits(ac97, AC97_POWERDOWN,
2355 AC97_PD_PR3, AC97_PD_PR3);
2356 }
2357 }
2358}
2359
2360
2172#ifdef CONFIG_PM 2361#ifdef CONFIG_PM
2173/** 2362/**
2174 * snd_ac97_suspend - General suspend function for AC97 codec 2363 * snd_ac97_suspend - General suspend function for AC97 codec
@@ -2484,6 +2673,7 @@ static int tune_mute_led(struct snd_ac97 *ac97)
2484 msw->put = master_mute_sw_put; 2673 msw->put = master_mute_sw_put;
2485 snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); 2674 snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
2486 snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ 2675 snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
2676 ac97->scaps |= AC97_SCAP_EAPD_LED;
2487 return 0; 2677 return 0;
2488} 2678}
2489 2679
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/intel8x0.c b/sound/pci/intel8x0.c
index 6874263f1681..72dbaedcbdf5 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -2251,6 +2251,16 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
2251 /* ACLink on, 2 channels */ 2251 /* ACLink on, 2 channels */
2252 cnt = igetdword(chip, ICHREG(GLOB_CNT)); 2252 cnt = igetdword(chip, ICHREG(GLOB_CNT));
2253 cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); 2253 cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
2254#ifdef CONFIG_SND_AC97_POWER_SAVE
2255 /* do cold reset - the full ac97 powerdown may leave the controller
2256 * in a warm state but actually it cannot communicate with the codec.
2257 */
2258 iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD);
2259 cnt = igetdword(chip, ICHREG(GLOB_CNT));
2260 udelay(10);
2261 iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
2262 msleep(1);
2263#else
2254 /* finish cold or do warm reset */ 2264 /* finish cold or do warm reset */
2255 cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; 2265 cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
2256 iputdword(chip, ICHREG(GLOB_CNT), cnt); 2266 iputdword(chip, ICHREG(GLOB_CNT), cnt);
@@ -2265,6 +2275,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
2265 return -EIO; 2275 return -EIO;
2266 2276
2267 __ok: 2277 __ok:
2278#endif
2268 if (probing) { 2279 if (probing) {
2269 /* wait for any codec ready status. 2280 /* wait for any codec ready status.
2270 * Once it becomes ready it should remain ready 2281 * Once it becomes ready it should remain ready
@@ -2485,7 +2496,7 @@ static int intel8x0_resume(struct pci_dev *pci)
2485 card->shortname, chip); 2496 card->shortname, chip);
2486 chip->irq = pci->irq; 2497 chip->irq = pci->irq;
2487 synchronize_irq(chip->irq); 2498 synchronize_irq(chip->irq);
2488 snd_intel8x0_chip_init(chip, 1); 2499 snd_intel8x0_chip_init(chip, 0);
2489 2500
2490 /* re-initialize mixer stuff */ 2501 /* re-initialize mixer stuff */
2491 if (chip->device_type == DEVICE_INTEL_ICH4) { 2502 if (chip->device_type == DEVICE_INTEL_ICH4) {
@@ -2615,6 +2626,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2615 /* not 48000Hz, tuning the clock.. */ 2626 /* not 48000Hz, tuning the clock.. */
2616 chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; 2627 chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
2617 printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); 2628 printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
2629 snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
2618} 2630}
2619 2631
2620#ifdef CONFIG_PROC_FS 2632#ifdef CONFIG_PROC_FS
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 08da9234efb3..2c23a665c3e3 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1277,7 +1277,18 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream)
1277 if (! ratep->used) 1277 if (! ratep->used)
1278 ratep->rate = 0; 1278 ratep->rate = 0;
1279 spin_unlock_irq(&ratep->lock); 1279 spin_unlock_irq(&ratep->lock);
1280 1280 if (! ratep->rate) {
1281 if (! viadev->direction) {
1282 snd_ac97_update_power(chip->ac97,
1283 AC97_PCM_FRONT_DAC_RATE, 0);
1284 snd_ac97_update_power(chip->ac97,
1285 AC97_PCM_SURR_DAC_RATE, 0);
1286 snd_ac97_update_power(chip->ac97,
1287 AC97_PCM_LFE_DAC_RATE, 0);
1288 } else
1289 snd_ac97_update_power(chip->ac97,
1290 AC97_PCM_LR_ADC_RATE, 0);
1291 }
1281 viadev->substream = NULL; 1292 viadev->substream = NULL;
1282 return 0; 1293 return 0;
1283} 1294}