From e3e9c5e7096f6379ca8fa78413b2055fa29f4530 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Wed, 28 Jan 2009 12:40:42 -0200 Subject: 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: Thadeu Lima de Souza Cascardo Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 68 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 19d3391e229f..b37bd268301f 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -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) -{ - unsigned long end_time; - unsigned int cnt, status, nstatus; - - /* 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); +#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 int cnt; /* ACLink on, 2 channels */ + + if (snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode)) + return -EIO; + 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 -- cgit v1.2.3 From e167280070cccd2e0cde94f73ded0a4b08bf6412 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jan 2009 16:05:16 +0100 Subject: ALSA: intel8x0 - Fix build with CONFIG_SND_AC97_POWERSAVE=n Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b37bd268301f..b13ef1e2a4a3 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2317,7 +2317,7 @@ static int snd_intel8x0_ich_chip_cold_reset(struct intel8x0 *chip) #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_cold_reset(chip) 0 #define snd_intel8x0_ich_chip_can_cold_reset(chip) (0) #endif -- cgit v1.2.3 From 328cc6dfaadad614449eca1c75559e64c5054fea Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Wed, 28 Jan 2009 15:39:22 -0200 Subject: ALSA: AC97: Print AC97 flags in proc file to make debug it easier While debugging some code paths in AC97 codec patches and its suspend and resume functions, getting to know the flags has proved useful to follow those code paths. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_proc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 060ea59d5f02..73b17d526c8b 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -125,6 +125,8 @@ static void snd_ac97_proc_read_main(struct snd_ac97 *ac97, struct snd_info_buffe snd_iprintf(buffer, "PCI Subsys Device: 0x%04x\n\n", ac97->subsystem_device); + snd_iprintf(buffer, "Flags: %x\n", ac97->flags); + if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23) { val = snd_ac97_read(ac97, AC97_INT_PAGING); snd_ac97_update_bits(ac97, AC97_INT_PAGING, -- cgit v1.2.3 From b833b5ec0411adc2255053a0e0ec536d97e5784e Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Wed, 28 Jan 2009 18:20:06 -0200 Subject: ALSA: AC97: Fix function name type in comment s/updat/update/ Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index e2b843b4f9d0..27551e963e52 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -383,7 +383,7 @@ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned sho EXPORT_SYMBOL(snd_ac97_update_bits); -/* no lock version - see snd_ac97_updat_bits() */ +/* no lock version - see snd_ac97_update_bits() */ int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value) { -- cgit v1.2.3 From 14ab08610971eb1db572ad8ca63acd13bc4d4caf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Feb 2009 16:09:57 +0100 Subject: ALSA: intel8x0 - Add missing KERN_* prefix to printk Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 11 +++++++---- sound/pci/intel8x0m.c | 14 ++++++++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b13ef1e2a4a3..0f7d12911904 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -689,7 +689,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ ichdev->fragsize >> ichdev->pos_shift); #if 0 - printk("bdbar[%i] = 0x%x [0x%x]\n", + printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]); #endif } @@ -701,8 +701,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; ichdev->position = 0; #if 0 - printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n", - ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1); + printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, " + "period_size1 = 0x%x\n", + ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, + ichdev->fragsize1); #endif /* clear interrupts */ iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); @@ -768,7 +770,8 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich ichdev->lvi_frag %= ichdev->frags; ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); #if 0 - printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", + printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, " + "all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR)); diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 93449e464566..7c819fd824a5 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -411,7 +411,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0m *chip, struct ichdev *ic bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + (((idx >> 1) * ichdev->fragsize) % ichdev->size)); bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ ichdev->fragsize >> chip->pcm_pos_shift); - // printk("bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]); + /* + printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n", + idx + 0, bdbar[idx + 0], bdbar[idx + 1]); + */ } ichdev->frags = ichdev->size / ichdev->fragsize; } @@ -421,8 +424,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0m *chip, struct ichdev *ic ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; ichdev->position = 0; #if 0 - printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n", - ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1); + printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, " + "period_size1 = 0x%x\n", + ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, + ichdev->fragsize1); #endif /* clear interrupts */ iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); @@ -465,7 +470,8 @@ static inline void snd_intel8x0_update(struct intel8x0m *chip, struct ichdev *ic ichdev->lvi_frag * ichdev->fragsize1); #if 0 - printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", + printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], " + "prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR)); -- cgit v1.2.3