Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+52 −16
Original line number Diff line number Diff line
@@ -2287,23 +2287,23 @@ static void do_ali_reset(struct intel8x0 *chip)
	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, status, nstatus;
	unsigned int cnt;
	/* ACLink on, 2 channels */

	/* 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_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
		return -EIO;

	/* ACLink on, 2 channels */
	cnt = igetdword(chip, ICHREG(GLOB_CNT));
	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.
	 */
@@ -2312,22 +2312,58 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
	udelay(10);
	iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
	msleep(1);
	return 0;
}
#define snd_intel8x0_ich_chip_can_cold_reset(chip) \
	(!snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
#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 */
	cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
	iputdword(chip, ICHREG(GLOB_CNT), cnt);
	end_time = (jiffies + (HZ / 4)) + 1;
	do {
		if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
			goto __ok;
			return 0;
		schedule_timeout_uninterruptible(1);
	} while (time_after_eq(end_time, jiffies));
	snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
		   igetdword(chip, ICHREG(GLOB_CNT)));
	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) {
		/* wait for any codec ready status.
		 * Once it becomes ready it should remain ready