mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 23:39:18 +00:00
[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>
This commit is contained in:
parent
2b29b13c57
commit
6dbe662874
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "control.h"
|
#include "control.h"
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
@ -140,6 +141,20 @@
|
|||||||
#define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */
|
#define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */
|
||||||
#define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */
|
#define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */
|
||||||
|
|
||||||
|
/* powerdown bits */
|
||||||
|
#define AC97_PD_ADC_STATUS 0x0001 /* ADC status (RO) */
|
||||||
|
#define AC97_PD_DAC_STATUS 0x0002 /* DAC status (RO) */
|
||||||
|
#define AC97_PD_MIXER_STATUS 0x0004 /* Analog mixer status (RO) */
|
||||||
|
#define AC97_PD_VREF_STATUS 0x0008 /* Vref status (RO) */
|
||||||
|
#define AC97_PD_PR0 0x0100 /* Power down PCM ADCs and input MUX */
|
||||||
|
#define AC97_PD_PR1 0x0200 /* Power down PCM front DAC */
|
||||||
|
#define AC97_PD_PR2 0x0400 /* Power down Mixer (Vref still on) */
|
||||||
|
#define AC97_PD_PR3 0x0800 /* Power down Mixer (Vref off) */
|
||||||
|
#define AC97_PD_PR4 0x1000 /* Power down AC-Link */
|
||||||
|
#define AC97_PD_PR5 0x2000 /* Disable internal clock usage */
|
||||||
|
#define AC97_PD_PR6 0x4000 /* Headphone amplifier */
|
||||||
|
#define AC97_PD_EAPD 0x8000 /* External Amplifer Power Down (EAPD) */
|
||||||
|
|
||||||
/* extended audio ID bit defines */
|
/* extended audio ID bit defines */
|
||||||
#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
|
#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
|
||||||
#define AC97_EI_DRA 0x0002 /* Double rate supported */
|
#define AC97_EI_DRA 0x0002 /* Double rate supported */
|
||||||
@ -359,6 +374,7 @@
|
|||||||
#define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */
|
#define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */
|
||||||
#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
|
#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
|
||||||
#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
|
#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
|
||||||
|
#define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */
|
||||||
|
|
||||||
/* ac97->flags */
|
/* ac97->flags */
|
||||||
#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
|
#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
|
||||||
@ -491,6 +507,12 @@ struct snd_ac97 {
|
|||||||
/* jack-sharing info */
|
/* jack-sharing info */
|
||||||
unsigned char indep_surround;
|
unsigned char indep_surround;
|
||||||
unsigned char channel_mode;
|
unsigned char channel_mode;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
unsigned int power_up; /* power states */
|
||||||
|
struct workqueue_struct *power_workq;
|
||||||
|
struct work_struct power_work;
|
||||||
|
#endif
|
||||||
struct device dev;
|
struct device dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -532,6 +554,15 @@ unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
|
|||||||
void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
||||||
int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
||||||
int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value);
|
int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup);
|
||||||
|
#else
|
||||||
|
static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg,
|
||||||
|
int powerup)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
void snd_ac97_suspend(struct snd_ac97 *ac97);
|
void snd_ac97_suspend(struct snd_ac97 *ac97);
|
||||||
void snd_ac97_resume(struct snd_ac97 *ac97);
|
void snd_ac97_resume(struct snd_ac97 *ac97);
|
||||||
@ -583,6 +614,7 @@ struct ac97_pcm {
|
|||||||
copy_flag: 1, /* lowlevel driver must fill all entries */
|
copy_flag: 1, /* lowlevel driver must fill all entries */
|
||||||
spdif: 1; /* spdif pcm */
|
spdif: 1; /* spdif pcm */
|
||||||
unsigned short aslots; /* active slots */
|
unsigned short aslots; /* active slots */
|
||||||
|
unsigned short cur_dbl; /* current double-rate state */
|
||||||
unsigned int rates; /* available rates */
|
unsigned int rates; /* available rates */
|
||||||
struct {
|
struct {
|
||||||
unsigned short slots; /* driver input: requested AC97 slot numbers */
|
unsigned short slots; /* driver input: requested AC97 slot numbers */
|
||||||
|
@ -100,4 +100,17 @@ config SND_MPU401
|
|||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called snd-mpu401.
|
will be called snd-mpu401.
|
||||||
|
|
||||||
|
config SND_AC97_POWER_SAVE
|
||||||
|
bool "AC97 Power-Saving Mode"
|
||||||
|
depends on SND_AC97_CODEC && EXPERIMENTAL
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Say Y here to enable the aggressive power-saving support of
|
||||||
|
AC97 codecs. In this mode, the power-mode is dynamically
|
||||||
|
controlled at each open/close.
|
||||||
|
|
||||||
|
The mode is activated by passing power_save=1 option to
|
||||||
|
snd-ac97-codec driver. You can toggle it dynamically over
|
||||||
|
sysfs, too.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -47,6 +47,11 @@ static int enable_loopback;
|
|||||||
module_param(enable_loopback, bool, 0444);
|
module_param(enable_loopback, bool, 0444);
|
||||||
MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
|
MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
static int power_save;
|
||||||
|
module_param(power_save, bool, 0644);
|
||||||
|
MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control");
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@ -187,6 +192,8 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void update_power_regs(struct snd_ac97 *ac97);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I/O routines
|
* I/O routines
|
||||||
*/
|
*/
|
||||||
@ -554,6 +561,18 @@ int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
|
|||||||
}
|
}
|
||||||
err = snd_ac97_update_bits(ac97, reg, val_mask, val);
|
err = snd_ac97_update_bits(ac97, reg, val_mask, val);
|
||||||
snd_ac97_page_restore(ac97, page_save);
|
snd_ac97_page_restore(ac97, page_save);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
/* check analog mixer power-down */
|
||||||
|
if ((val_mask & 0x8000) &&
|
||||||
|
(kcontrol->private_value & (1<<30))) {
|
||||||
|
if (val & 0x8000)
|
||||||
|
ac97->power_up &= ~(1 << (reg>>1));
|
||||||
|
else
|
||||||
|
ac97->power_up |= 1 << (reg>>1);
|
||||||
|
if (power_save)
|
||||||
|
update_power_regs(ac97);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,6 +981,10 @@ static int snd_ac97_bus_dev_free(struct snd_device *device)
|
|||||||
static int snd_ac97_free(struct snd_ac97 *ac97)
|
static int snd_ac97_free(struct snd_ac97 *ac97)
|
||||||
{
|
{
|
||||||
if (ac97) {
|
if (ac97) {
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
if (ac97->power_workq)
|
||||||
|
destroy_workqueue(ac97->power_workq);
|
||||||
|
#endif
|
||||||
snd_ac97_proc_done(ac97);
|
snd_ac97_proc_done(ac97);
|
||||||
if (ac97->bus)
|
if (ac97->bus)
|
||||||
ac97->bus->codec[ac97->num] = NULL;
|
ac97->bus->codec[ac97->num] = NULL;
|
||||||
@ -1117,7 +1140,9 @@ struct snd_kcontrol *snd_ac97_cnew(const struct snd_kcontrol_new *_template, str
|
|||||||
/*
|
/*
|
||||||
* create mute switch(es) for normal stereo controls
|
* create mute switch(es) for normal stereo controls
|
||||||
*/
|
*/
|
||||||
static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, int check_stereo, struct snd_ac97 *ac97)
|
static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
|
||||||
|
int check_stereo, int check_amix,
|
||||||
|
struct snd_ac97 *ac97)
|
||||||
{
|
{
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
int err;
|
int err;
|
||||||
@ -1137,10 +1162,14 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
|
|||||||
}
|
}
|
||||||
if (mute_mask == 0x8080) {
|
if (mute_mask == 0x8080) {
|
||||||
struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
|
struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
|
||||||
|
if (check_amix)
|
||||||
|
tmp.private_value |= (1 << 30);
|
||||||
tmp.index = ac97->num;
|
tmp.index = ac97->num;
|
||||||
kctl = snd_ctl_new1(&tmp, ac97);
|
kctl = snd_ctl_new1(&tmp, ac97);
|
||||||
} else {
|
} else {
|
||||||
struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1);
|
struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1);
|
||||||
|
if (check_amix)
|
||||||
|
tmp.private_value |= (1 << 30);
|
||||||
tmp.index = ac97->num;
|
tmp.index = ac97->num;
|
||||||
kctl = snd_ctl_new1(&tmp, ac97);
|
kctl = snd_ctl_new1(&tmp, ac97);
|
||||||
}
|
}
|
||||||
@ -1186,7 +1215,9 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne
|
|||||||
/*
|
/*
|
||||||
* create a mute-switch and a volume for normal stereo/mono controls
|
* create a mute-switch and a volume for normal stereo/mono controls
|
||||||
*/
|
*/
|
||||||
static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, struct snd_ac97 *ac97)
|
static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx,
|
||||||
|
int reg, int check_stereo, int check_amix,
|
||||||
|
struct snd_ac97 *ac97)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char name[44];
|
char name[44];
|
||||||
@ -1197,7 +1228,9 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int
|
|||||||
|
|
||||||
if (snd_ac97_try_bit(ac97, reg, 15)) {
|
if (snd_ac97_try_bit(ac97, reg, 15)) {
|
||||||
sprintf(name, "%s Switch", pfx);
|
sprintf(name, "%s Switch", pfx);
|
||||||
if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0)
|
if ((err = snd_ac97_cmute_new_stereo(card, name, reg,
|
||||||
|
check_stereo, check_amix,
|
||||||
|
ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
check_volume_resolution(ac97, reg, &lo_max, &hi_max);
|
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
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97)
|
#define snd_ac97_cmix_new(card, pfx, reg, acheck, ac97) \
|
||||||
#define snd_ac97_cmute_new(card, name, reg, ac97) snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97)
|
snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97)
|
||||||
|
#define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \
|
||||||
|
snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97)
|
||||||
|
|
||||||
static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);
|
static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);
|
||||||
|
|
||||||
@ -1226,9 +1261,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
/* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */
|
/* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
|
||||||
if (ac97->flags & AC97_HAS_NO_MASTER_VOL)
|
if (ac97->flags & AC97_HAS_NO_MASTER_VOL)
|
||||||
err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, ac97);
|
err = snd_ac97_cmute_new(card, "Master Playback Switch",
|
||||||
|
AC97_MASTER, 0, ac97);
|
||||||
else
|
else
|
||||||
err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97);
|
err = snd_ac97_cmix_new(card, "Master Playback",
|
||||||
|
AC97_MASTER, 0, ac97);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1265,19 +1302,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER))
|
if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER))
|
||||||
&& !(ac97->flags & AC97_AD_MULTI)) {
|
&& !(ac97->flags & AC97_AD_MULTI)) {
|
||||||
/* Surround Master (0x38) is with stereo mutes */
|
/* Surround Master (0x38) is with stereo mutes */
|
||||||
if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback",
|
||||||
|
AC97_SURROUND_MASTER, 1, 0,
|
||||||
|
ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build headphone controls */
|
/* build headphone controls */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Headphone Playback",
|
||||||
|
AC97_HEADPHONE, 0, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build master mono controls */
|
/* build master mono controls */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Master Mono Playback",
|
||||||
|
AC97_MASTER_MONO, 0, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1310,7 +1351,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
/* build Phone controls */
|
/* build Phone controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_PHONE)) {
|
if (!(ac97->flags & AC97_HAS_NO_PHONE)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Phone Playback",
|
||||||
|
AC97_PHONE, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1318,7 +1360,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
/* build MIC controls */
|
/* build MIC controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_MIC)) {
|
if (!(ac97->flags & AC97_HAS_NO_MIC)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Mic Playback",
|
||||||
|
AC97_MIC, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
@ -1327,14 +1370,16 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
|
|
||||||
/* build Line controls */
|
/* build Line controls */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Line Playback",
|
||||||
|
AC97_LINE, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build CD controls */
|
/* build CD controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_CD)) {
|
if (!(ac97->flags & AC97_HAS_NO_CD)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "CD Playback",
|
||||||
|
AC97_CD, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1342,7 +1387,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
/* build Video controls */
|
/* build Video controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_VIDEO)) {
|
if (!(ac97->flags & AC97_HAS_NO_VIDEO)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Video Playback",
|
||||||
|
AC97_VIDEO, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1350,7 +1396,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
/* build Aux controls */
|
/* build Aux controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_AUX)) {
|
if (!(ac97->flags & AC97_HAS_NO_AUX)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Aux Playback",
|
||||||
|
AC97_AUX, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1385,9 +1432,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
} else {
|
} else {
|
||||||
if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
|
if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
|
||||||
if (ac97->flags & AC97_HAS_NO_PCM_VOL)
|
if (ac97->flags & AC97_HAS_NO_PCM_VOL)
|
||||||
err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
|
err = snd_ac97_cmute_new(card,
|
||||||
|
"PCM Playback Switch",
|
||||||
|
AC97_PCM, 0, ac97);
|
||||||
else
|
else
|
||||||
err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
|
err = snd_ac97_cmix_new(card, "PCM Playback",
|
||||||
|
AC97_PCM, 0, ac97);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1398,7 +1448,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
|||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) {
|
if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) {
|
||||||
if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0)
|
err = snd_ac97_cmute_new(card, "Capture Switch",
|
||||||
|
AC97_REC_GAIN, 0, ac97);
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
|
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)
|
|||||||
/* build_ops to do nothing */
|
/* build_ops to do nothing */
|
||||||
static struct snd_ac97_build_ops null_build_ops;
|
static struct snd_ac97_build_ops null_build_ops;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
static void do_update_power(void *data)
|
||||||
|
{
|
||||||
|
update_power_regs(data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_ac97_mixer - create an Codec97 component
|
* snd_ac97_mixer - create an Codec97 component
|
||||||
* @bus: the AC97 bus which codec is attached to
|
* @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,
|
|||||||
bus->codec[ac97->num] = ac97;
|
bus->codec[ac97->num] = ac97;
|
||||||
mutex_init(&ac97->reg_mutex);
|
mutex_init(&ac97->reg_mutex);
|
||||||
mutex_init(&ac97->page_mutex);
|
mutex_init(&ac97->page_mutex);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
ac97->power_workq = create_workqueue("ac97");
|
||||||
|
INIT_WORK(&ac97->power_work, do_update_power, ac97);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
if (ac97->pci) {
|
if (ac97->pci) {
|
||||||
@ -2117,15 +2180,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* make sure the proper powerdown bits are cleared */
|
if (ac97_is_audio(ac97))
|
||||||
if (ac97->scaps && ac97_is_audio(ac97)) {
|
update_power_regs(ac97);
|
||||||
reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
|
|
||||||
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
|
||||||
reg &= ~AC97_EA_PRJ;
|
|
||||||
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
|
||||||
reg &= ~(AC97_EA_PRI | AC97_EA_PRK);
|
|
||||||
snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg);
|
|
||||||
}
|
|
||||||
snd_ac97_proc_init(ac97);
|
snd_ac97_proc_init(ac97);
|
||||||
if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) {
|
if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) {
|
||||||
snd_ac97_free(ac97);
|
snd_ac97_free(ac97);
|
||||||
@ -2153,22 +2209,155 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
|
|||||||
snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f);
|
snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f);
|
||||||
}
|
}
|
||||||
|
|
||||||
power = ac97->regs[AC97_POWERDOWN] | 0x8000; /* EAPD */
|
/* surround, CLFE, mic powerdown */
|
||||||
power |= 0x4000; /* Headphone amplifier powerdown */
|
power = ac97->regs[AC97_EXTENDED_STATUS];
|
||||||
power |= 0x0300; /* ADC & DAC powerdown */
|
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
||||||
|
power |= AC97_EA_PRJ;
|
||||||
|
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
||||||
|
power |= AC97_EA_PRI | AC97_EA_PRK;
|
||||||
|
power |= AC97_EA_PRL;
|
||||||
|
snd_ac97_write(ac97, AC97_EXTENDED_STATUS, power);
|
||||||
|
|
||||||
|
/* powerdown external amplifier */
|
||||||
|
if (ac97->scaps & AC97_SCAP_INV_EAPD)
|
||||||
|
power = ac97->regs[AC97_POWERDOWN] & ~AC97_PD_EAPD;
|
||||||
|
else if (! (ac97->scaps & AC97_SCAP_EAPD_LED))
|
||||||
|
power = ac97->regs[AC97_POWERDOWN] | AC97_PD_EAPD;
|
||||||
|
power |= AC97_PD_PR6; /* Headphone amplifier powerdown */
|
||||||
|
power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */
|
||||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||||
udelay(100);
|
udelay(100);
|
||||||
power |= 0x0400; /* Analog Mixer powerdown (Vref on) */
|
power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
|
||||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
|
||||||
udelay(100);
|
|
||||||
#if 0
|
|
||||||
/* FIXME: this causes click noises on some boards at resume */
|
|
||||||
power |= 0x3800; /* AC-link powerdown, internal Clk disable */
|
|
||||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
if (power_save) {
|
||||||
|
udelay(100);
|
||||||
|
/* AC-link powerdown, internal Clk disable */
|
||||||
|
/* FIXME: this may cause click noises on some boards */
|
||||||
|
power |= AC97_PD_PR4 | AC97_PD_PR5;
|
||||||
|
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ac97_power_reg {
|
||||||
|
unsigned short reg;
|
||||||
|
unsigned short power_reg;
|
||||||
|
unsigned short mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { PWIDX_ADC, PWIDX_FRONT, PWIDX_CLFE, PWIDX_SURR, PWIDX_MIC, PWIDX_SIZE };
|
||||||
|
|
||||||
|
static struct ac97_power_reg power_regs[PWIDX_SIZE] = {
|
||||||
|
[PWIDX_ADC] = { AC97_PCM_LR_ADC_RATE, AC97_POWERDOWN, AC97_PD_PR0},
|
||||||
|
[PWIDX_FRONT] = { AC97_PCM_FRONT_DAC_RATE, AC97_POWERDOWN, AC97_PD_PR1},
|
||||||
|
[PWIDX_CLFE] = { AC97_PCM_LFE_DAC_RATE, AC97_EXTENDED_STATUS,
|
||||||
|
AC97_EA_PRI | AC97_EA_PRK},
|
||||||
|
[PWIDX_SURR] = { AC97_PCM_SURR_DAC_RATE, AC97_EXTENDED_STATUS,
|
||||||
|
AC97_EA_PRJ},
|
||||||
|
[PWIDX_MIC] = { AC97_PCM_MIC_ADC_RATE, AC97_EXTENDED_STATUS,
|
||||||
|
AC97_EA_PRL},
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
/**
|
||||||
|
* snd_ac97_update_power - update the powerdown register
|
||||||
|
* @ac97: the codec instance
|
||||||
|
* @reg: the rate register, e.g. AC97_PCM_FRONT_DAC_RATE
|
||||||
|
* @powerup: non-zero when power up the part
|
||||||
|
*
|
||||||
|
* Update the AC97 powerdown register bits of the given part.
|
||||||
|
*/
|
||||||
|
int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (! ac97)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (reg) {
|
||||||
|
/* SPDIF requires DAC power, too */
|
||||||
|
if (reg == AC97_SPDIF)
|
||||||
|
reg = AC97_PCM_FRONT_DAC_RATE;
|
||||||
|
for (i = 0; i < PWIDX_SIZE; i++) {
|
||||||
|
if (power_regs[i].reg == reg) {
|
||||||
|
if (powerup)
|
||||||
|
ac97->power_up |= (1 << i);
|
||||||
|
else
|
||||||
|
ac97->power_up &= ~(1 << i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! power_save)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (! powerup && ac97->power_workq)
|
||||||
|
/* adjust power-down bits after two seconds delay
|
||||||
|
* (for avoiding loud click noises for many (OSS) apps
|
||||||
|
* that open/close frequently)
|
||||||
|
*/
|
||||||
|
queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
|
||||||
|
else
|
||||||
|
update_power_regs(ac97);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_ac97_update_power);
|
||||||
|
#endif /* CONFIG_SND_AC97_POWER_SAVE */
|
||||||
|
|
||||||
|
static void update_power_regs(struct snd_ac97 *ac97)
|
||||||
|
{
|
||||||
|
unsigned int power_up, bits;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
if (power_save)
|
||||||
|
power_up = ac97->power_up;
|
||||||
|
else {
|
||||||
|
#endif
|
||||||
|
power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
|
||||||
|
power_up |= (1 << PWIDX_MIC);
|
||||||
|
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
||||||
|
power_up |= (1 << PWIDX_SURR);
|
||||||
|
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
||||||
|
power_up |= (1 << PWIDX_CLFE);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (power_up) {
|
||||||
|
if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
|
||||||
|
/* needs power-up analog mix and vref */
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR3, 0);
|
||||||
|
msleep(1);
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR2, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < PWIDX_SIZE; i++) {
|
||||||
|
if (power_up & (1 << i))
|
||||||
|
bits = 0;
|
||||||
|
else
|
||||||
|
bits = power_regs[i].mask;
|
||||||
|
snd_ac97_update_bits(ac97, power_regs[i].power_reg,
|
||||||
|
power_regs[i].mask, bits);
|
||||||
|
}
|
||||||
|
if (! power_up) {
|
||||||
|
if (! (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2)) {
|
||||||
|
/* power down analog mix and vref */
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR2, AC97_PD_PR2);
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR3, AC97_PD_PR3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
/**
|
/**
|
||||||
* snd_ac97_suspend - General suspend function for AC97 codec
|
* snd_ac97_suspend - General suspend function for AC97 codec
|
||||||
@ -2484,6 +2673,7 @@ static int tune_mute_led(struct snd_ac97 *ac97)
|
|||||||
msw->put = master_mute_sw_put;
|
msw->put = master_mute_sw_put;
|
||||||
snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
|
snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
|
||||||
snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
|
||||||
|
ac97->scaps |= AC97_SCAP_EAPD_LED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,6 +269,7 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snd_ac97_update_power(ac97, reg, 1);
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case AC97_PCM_MIC_ADC_RATE:
|
case AC97_PCM_MIC_ADC_RATE:
|
||||||
if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */
|
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,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pcm->cur_dbl = r;
|
||||||
spin_unlock_irq(&pcm->bus->bus_lock);
|
spin_unlock_irq(&pcm->bus->bus_lock);
|
||||||
for (i = 3; i < 12; i++) {
|
for (i = 3; i < 12; i++) {
|
||||||
if (!(slots & (1 << i)))
|
if (!(slots & (1 << i)))
|
||||||
@ -651,6 +653,21 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
|
|||||||
unsigned short slots = pcm->aslots;
|
unsigned short slots = pcm->aslots;
|
||||||
int i, cidx;
|
int i, cidx;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
int r = pcm->cur_dbl;
|
||||||
|
for (i = 3; i < 12; i++) {
|
||||||
|
if (!(slots & (1 << i)))
|
||||||
|
continue;
|
||||||
|
for (cidx = 0; cidx < 4; cidx++) {
|
||||||
|
if (pcm->r[r].rslots[cidx] & (1 << i)) {
|
||||||
|
int reg = get_slot_reg(pcm, cidx, i, r);
|
||||||
|
snd_ac97_update_power(pcm->r[r].codec[cidx],
|
||||||
|
reg, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bus = pcm->bus;
|
bus = pcm->bus;
|
||||||
spin_lock_irq(&pcm->bus->bus_lock);
|
spin_lock_irq(&pcm->bus->bus_lock);
|
||||||
for (i = 3; i < 12; i++) {
|
for (i = 3; i < 12; i++) {
|
||||||
@ -660,6 +677,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
|
|||||||
bus->used_slots[pcm->stream][cidx] &= ~(1 << i);
|
bus->used_slots[pcm->stream][cidx] &= ~(1 << i);
|
||||||
}
|
}
|
||||||
pcm->aslots = 0;
|
pcm->aslots = 0;
|
||||||
|
pcm->cur_dbl = 0;
|
||||||
spin_unlock_irq(&pcm->bus->bus_lock);
|
spin_unlock_irq(&pcm->bus->bus_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2251,6 +2251,16 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
|
|||||||
/* ACLink on, 2 channels */
|
/* ACLink on, 2 channels */
|
||||||
cnt = igetdword(chip, ICHREG(GLOB_CNT));
|
cnt = igetdword(chip, ICHREG(GLOB_CNT));
|
||||||
cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
|
cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
/* do cold reset - the full ac97 powerdown may leave the controller
|
||||||
|
* in a warm state but actually it cannot communicate with the codec.
|
||||||
|
*/
|
||||||
|
iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD);
|
||||||
|
cnt = igetdword(chip, ICHREG(GLOB_CNT));
|
||||||
|
udelay(10);
|
||||||
|
iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
|
||||||
|
msleep(1);
|
||||||
|
#else
|
||||||
/* finish cold or do warm reset */
|
/* finish cold or do warm reset */
|
||||||
cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
|
cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
|
||||||
iputdword(chip, ICHREG(GLOB_CNT), cnt);
|
iputdword(chip, ICHREG(GLOB_CNT), cnt);
|
||||||
@ -2265,6 +2275,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
__ok:
|
__ok:
|
||||||
|
#endif
|
||||||
if (probing) {
|
if (probing) {
|
||||||
/* wait for any codec ready status.
|
/* wait for any codec ready status.
|
||||||
* Once it becomes ready it should remain ready
|
* Once it becomes ready it should remain ready
|
||||||
@ -2485,7 +2496,7 @@ static int intel8x0_resume(struct pci_dev *pci)
|
|||||||
card->shortname, chip);
|
card->shortname, chip);
|
||||||
chip->irq = pci->irq;
|
chip->irq = pci->irq;
|
||||||
synchronize_irq(chip->irq);
|
synchronize_irq(chip->irq);
|
||||||
snd_intel8x0_chip_init(chip, 1);
|
snd_intel8x0_chip_init(chip, 0);
|
||||||
|
|
||||||
/* re-initialize mixer stuff */
|
/* re-initialize mixer stuff */
|
||||||
if (chip->device_type == DEVICE_INTEL_ICH4) {
|
if (chip->device_type == DEVICE_INTEL_ICH4) {
|
||||||
@ -2615,6 +2626,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
|
|||||||
/* not 48000Hz, tuning the clock.. */
|
/* not 48000Hz, tuning the clock.. */
|
||||||
chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
|
chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
|
||||||
printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
|
printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
|
||||||
|
snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
|
@ -1277,7 +1277,18 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream)
|
|||||||
if (! ratep->used)
|
if (! ratep->used)
|
||||||
ratep->rate = 0;
|
ratep->rate = 0;
|
||||||
spin_unlock_irq(&ratep->lock);
|
spin_unlock_irq(&ratep->lock);
|
||||||
|
if (! ratep->rate) {
|
||||||
|
if (! viadev->direction) {
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_FRONT_DAC_RATE, 0);
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_SURR_DAC_RATE, 0);
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_LFE_DAC_RATE, 0);
|
||||||
|
} else
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_LR_ADC_RATE, 0);
|
||||||
|
}
|
||||||
viadev->substream = NULL;
|
viadev->substream = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user