aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorThadeu Lima de Souza Cascardo <cascardo@holoscopio.com>2009-01-28 09:40:42 -0500
committerTakashi Iwai <tiwai@suse.de>2009-01-28 09:56:32 -0500
commite3e9c5e7096f6379ca8fa78413b2055fa29f4530 (patch)
tree36ea34ad07dcf96ea7f4ac5ef1b2f8dc1e3fcc93 /sound
parent1de9e8e70f5acc441550ca75433563d91b269bbe (diff)
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 <cascardo@holoscopio.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/intel8x0.c68
1 files 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)
2287 iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000); 2287 iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000);
2288} 2288}
2289 2289
2290static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) 2290#ifdef CONFIG_SND_AC97_POWER_SAVE
2291{ 2291static struct snd_pci_quirk ich_chip_reset_mode[] = {
2292 unsigned long end_time; 2292 SND_PCI_QUIRK(0x1014, 0x051f, "Thinkpad R32", 1),
2293 unsigned int cnt, status, nstatus; 2293 { } /* end */
2294 2294};
2295 /* put logic to right state */
2296 /* first clear status bits */
2297 status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
2298 if (chip->device_type == DEVICE_NFORCE)
2299 status |= ICH_NVSPINT;
2300 cnt = igetdword(chip, ICHREG(GLOB_STA));
2301 iputdword(chip, ICHREG(GLOB_STA), cnt & status);
2302 2295
2296static int snd_intel8x0_ich_chip_cold_reset(struct intel8x0 *chip)
2297{
2298 unsigned int cnt;
2303 /* ACLink on, 2 channels */ 2299 /* ACLink on, 2 channels */
2300
2301 if (snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
2302 return -EIO;
2303
2304 cnt = igetdword(chip, ICHREG(GLOB_CNT)); 2304 cnt = igetdword(chip, ICHREG(GLOB_CNT));
2305 cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); 2305 cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
2306#ifdef CONFIG_SND_AC97_POWER_SAVE 2306
2307 /* do cold reset - the full ac97 powerdown may leave the controller 2307 /* do cold reset - the full ac97 powerdown may leave the controller
2308 * in a warm state but actually it cannot communicate with the codec. 2308 * in a warm state but actually it cannot communicate with the codec.
2309 */ 2309 */
@@ -2312,22 +2312,58 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
2312 udelay(10); 2312 udelay(10);
2313 iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); 2313 iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
2314 msleep(1); 2314 msleep(1);
2315 return 0;
2316}
2317#define snd_intel8x0_ich_chip_can_cold_reset(chip) \
2318 (!snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
2315#else 2319#else
2320#define snd_intel8x0_ich_chip_cold_reset(x) do { } while (0)
2321#define snd_intel8x0_ich_chip_can_cold_reset(chip) (0)
2322#endif
2323
2324static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip)
2325{
2326 unsigned long end_time;
2327 unsigned int cnt;
2328 /* ACLink on, 2 channels */
2329 cnt = igetdword(chip, ICHREG(GLOB_CNT));
2330 cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
2316 /* finish cold or do warm reset */ 2331 /* finish cold or do warm reset */
2317 cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; 2332 cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
2318 iputdword(chip, ICHREG(GLOB_CNT), cnt); 2333 iputdword(chip, ICHREG(GLOB_CNT), cnt);
2319 end_time = (jiffies + (HZ / 4)) + 1; 2334 end_time = (jiffies + (HZ / 4)) + 1;
2320 do { 2335 do {
2321 if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) 2336 if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
2322 goto __ok; 2337 return 0;
2323 schedule_timeout_uninterruptible(1); 2338 schedule_timeout_uninterruptible(1);
2324 } while (time_after_eq(end_time, jiffies)); 2339 } while (time_after_eq(end_time, jiffies));
2325 snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", 2340 snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
2326 igetdword(chip, ICHREG(GLOB_CNT))); 2341 igetdword(chip, ICHREG(GLOB_CNT)));
2327 return -EIO; 2342 return -EIO;
2343}
2344
2345static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
2346{
2347 unsigned long end_time;
2348 unsigned int status, nstatus;
2349 unsigned int cnt;
2350 int err;
2351
2352 /* put logic to right state */
2353 /* first clear status bits */
2354 status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
2355 if (chip->device_type == DEVICE_NFORCE)
2356 status |= ICH_NVSPINT;
2357 cnt = igetdword(chip, ICHREG(GLOB_STA));
2358 iputdword(chip, ICHREG(GLOB_STA), cnt & status);
2359
2360 if (snd_intel8x0_ich_chip_can_cold_reset(chip))
2361 err = snd_intel8x0_ich_chip_cold_reset(chip);
2362 else
2363 err = snd_intel8x0_ich_chip_reset(chip);
2364 if (err < 0)
2365 return err;
2328 2366
2329 __ok:
2330#endif
2331 if (probing) { 2367 if (probing) {
2332 /* wait for any codec ready status. 2368 /* wait for any codec ready status.
2333 * Once it becomes ready it should remain ready 2369 * Once it becomes ready it should remain ready