Commit e3e9c5e7 authored by Thadeu Lima de Souza Cascardo's avatar Thadeu Lima de Souza Cascardo Committed by Takashi Iwai

ALSA: Don't cold reset AC97 codecs in some ICH chipsets

Check in a quirk list if it should do cold reset when AC97 power saving
is enabled. Some devices do not resume properly when cold reset,
although power saving works OK.
Signed-off-by: default avatarThadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 1de9e8e7
...@@ -2287,23 +2287,23 @@ static void do_ali_reset(struct intel8x0 *chip) ...@@ -2287,23 +2287,23 @@ static void do_ali_reset(struct intel8x0 *chip)
iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000); iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000);
} }
static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) #ifdef CONFIG_SND_AC97_POWER_SAVE
static struct snd_pci_quirk ich_chip_reset_mode[] = {
SND_PCI_QUIRK(0x1014, 0x051f, "Thinkpad R32", 1),
{ } /* end */
};
static int snd_intel8x0_ich_chip_cold_reset(struct intel8x0 *chip)
{ {
unsigned long end_time; unsigned int cnt;
unsigned int cnt, status, nstatus; /* ACLink on, 2 channels */
/* put logic to right state */ if (snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
/* first clear status bits */ return -EIO;
status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
if (chip->device_type == DEVICE_NFORCE)
status |= ICH_NVSPINT;
cnt = igetdword(chip, ICHREG(GLOB_STA));
iputdword(chip, ICHREG(GLOB_STA), cnt & status);
/* 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 /* do cold reset - the full ac97 powerdown may leave the controller
* in a warm state but actually it cannot communicate with the codec. * in a warm state but actually it cannot communicate with the codec.
*/ */
...@@ -2312,22 +2312,58 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) ...@@ -2312,22 +2312,58 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
udelay(10); udelay(10);
iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
msleep(1); msleep(1);
return 0;
}
#define snd_intel8x0_ich_chip_can_cold_reset(chip) \
(!snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
#else #else
#define snd_intel8x0_ich_chip_cold_reset(x) do { } while (0)
#define snd_intel8x0_ich_chip_can_cold_reset(chip) (0)
#endif
static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip)
{
unsigned long end_time;
unsigned int cnt;
/* ACLink on, 2 channels */
cnt = igetdword(chip, ICHREG(GLOB_CNT));
cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
/* 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);
end_time = (jiffies + (HZ / 4)) + 1; end_time = (jiffies + (HZ / 4)) + 1;
do { do {
if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
goto __ok; return 0;
schedule_timeout_uninterruptible(1); schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies)); } while (time_after_eq(end_time, jiffies));
snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
igetdword(chip, ICHREG(GLOB_CNT))); igetdword(chip, ICHREG(GLOB_CNT)));
return -EIO; return -EIO;
}
static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
{
unsigned long end_time;
unsigned int status, nstatus;
unsigned int cnt;
int err;
/* put logic to right state */
/* first clear status bits */
status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
if (chip->device_type == DEVICE_NFORCE)
status |= ICH_NVSPINT;
cnt = igetdword(chip, ICHREG(GLOB_STA));
iputdword(chip, ICHREG(GLOB_STA), cnt & status);
if (snd_intel8x0_ich_chip_can_cold_reset(chip))
err = snd_intel8x0_ich_chip_cold_reset(chip);
else
err = snd_intel8x0_ich_chip_reset(chip);
if (err < 0)
return err;
__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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment