diff options
author | Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com> | 2009-01-28 09:40:42 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-01-28 09:56:32 -0500 |
commit | e3e9c5e7096f6379ca8fa78413b2055fa29f4530 (patch) | |
tree | 36ea34ad07dcf96ea7f4ac5ef1b2f8dc1e3fcc93 /sound/pci | |
parent | 1de9e8e70f5acc441550ca75433563d91b269bbe (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/pci')
-rw-r--r-- | sound/pci/intel8x0.c | 68 |
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 | ||
2290 | static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | 2290 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
2291 | { | 2291 | static 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 | ||
2296 | static 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 | |||
2324 | static 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 | |||
2345 | static 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 |