diff options
author | Jaya Kumar <jayakumar.alsa@gmail.com> | 2006-04-28 08:34:49 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-06-22 15:32:49 -0400 |
commit | 9ac25594e68a4b61516e7c1140d8c0f7ef449e20 (patch) | |
tree | 628040fb065b882191a6ff5ed7aba42ef04b99d6 | |
parent | 5e1b1518a53fc62d9f39a13819c849336c6d8dd4 (diff) |
[ALSA] PM support for cs5535audio
Appended is my patch adding PM support to the cs5535audio driver.
I also added the ac97 quirk but it's not yet confirmed which
boards need to be in the quirk list. The patch also includes some
Kconfig and misc cleanup.
Signed-off-by: Jaya Kumar <jayakumar.alsa@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/Kconfig | 9 | ||||
-rw-r--r-- | sound/pci/cs5535audio/Makefile | 4 | ||||
-rw-r--r-- | sound/pci/cs5535audio/cs5535audio.c | 31 | ||||
-rw-r--r-- | sound/pci/cs5535audio/cs5535audio.h | 8 | ||||
-rw-r--r-- | sound/pci/cs5535audio/cs5535audio_pcm.c | 24 | ||||
-rw-r--r-- | sound/pci/cs5535audio/cs5535audio_pm.c | 123 |
6 files changed, 191 insertions, 8 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index a2081803a827..d37346b12dc0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -216,14 +216,19 @@ config SND_CS46XX_NEW_DSP | |||
216 | This works better than the old code, so say Y. | 216 | This works better than the old code, so say Y. |
217 | 217 | ||
218 | config SND_CS5535AUDIO | 218 | config SND_CS5535AUDIO |
219 | tristate "CS5535 Audio" | 219 | tristate "CS5535/CS5536 Audio" |
220 | depends on SND && X86 && !X86_64 | 220 | depends on SND && X86 && !X86_64 |
221 | select SND_PCM | 221 | select SND_PCM |
222 | select SND_AC97_CODEC | 222 | select SND_AC97_CODEC |
223 | help | 223 | help |
224 | Say Y here to include support for audio on CS5535 chips. It is | 224 | Say Y here to include support for audio on CS5535 chips. It is |
225 | referred to as NS CS5535 IO or AMD CS5535 IO companion in | 225 | referred to as NS CS5535 IO or AMD CS5535 IO companion in |
226 | various literature. | 226 | various literature. This driver also supports the CS5536 audio |
227 | device. However, for both chips, on certain boards, you may | ||
228 | need to use ac97_quirk=hp_only if your board has physically | ||
229 | mapped headphone out to master output. If that works for you, | ||
230 | send lspci -vvv output to the mailing list so that your board | ||
231 | can be identified in the quirks list. | ||
227 | 232 | ||
228 | To compile this driver as a module, choose M here: the module | 233 | To compile this driver as a module, choose M here: the module |
229 | will be called snd-cs5535audio. | 234 | will be called snd-cs5535audio. |
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index 08d8ee6547d3..2911a8adc1f2 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile | |||
@@ -4,5 +4,9 @@ | |||
4 | 4 | ||
5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o | 5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o |
6 | 6 | ||
7 | ifdef CONFIG_PM | ||
8 | snd-cs5535audio-objs += cs5535audio_pm.o | ||
9 | endif | ||
10 | |||
7 | # Toplevel Module Dependency | 11 | # Toplevel Module Dependency |
8 | obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o | 12 | obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o |
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 2c1213a35dcc..41f02f05dfdc 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for audio on multifunction CS5535 companion device | 2 | * Driver for audio on multifunction CS5535/6 companion device |
3 | * Copyright (C) Jaya Kumar | 3 | * Copyright (C) Jaya Kumar |
4 | * | 4 | * |
5 | * Based on Jaroslav Kysela and Takashi Iwai's examples. | 5 | * Based on Jaroslav Kysela and Takashi Iwai's examples. |
@@ -40,16 +40,29 @@ | |||
40 | 40 | ||
41 | #define DRIVER_NAME "cs5535audio" | 41 | #define DRIVER_NAME "cs5535audio" |
42 | 42 | ||
43 | static char *ac97_quirk; | ||
44 | module_param(ac97_quirk, charp, 0444); | ||
45 | MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds."); | ||
46 | |||
47 | static struct ac97_quirk ac97_quirks[] __devinitdata = { | ||
48 | #if 0 /* Not yet confirmed if all 5536 boards are HP only */ | ||
49 | { | ||
50 | .subvendor = PCI_VENDOR_ID_AMD, | ||
51 | .subdevice = PCI_DEVICE_ID_AMD_CS5536_AUDIO, | ||
52 | .name = "AMD RDK", | ||
53 | .type = AC97_TUNE_HP_ONLY | ||
54 | }, | ||
55 | #endif | ||
56 | {} | ||
57 | }; | ||
43 | 58 | ||
44 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 59 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
45 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 60 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
46 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 61 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
47 | 62 | ||
48 | static struct pci_device_id snd_cs5535audio_ids[] __devinitdata = { | 63 | static struct pci_device_id snd_cs5535audio_ids[] __devinitdata = { |
49 | { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO, | 64 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, |
50 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 65 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, |
51 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO, | ||
52 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
53 | {} | 66 | {} |
54 | }; | 67 | }; |
55 | 68 | ||
@@ -148,6 +161,8 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) | |||
148 | return err; | 161 | return err; |
149 | } | 162 | } |
150 | 163 | ||
164 | snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk); | ||
165 | |||
151 | return 0; | 166 | return 0; |
152 | } | 167 | } |
153 | 168 | ||
@@ -347,6 +362,8 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci, | |||
347 | if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0) | 362 | if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0) |
348 | goto probefail_out; | 363 | goto probefail_out; |
349 | 364 | ||
365 | card->private_data = cs5535au; | ||
366 | |||
350 | if ((err = snd_cs5535audio_mixer(cs5535au)) < 0) | 367 | if ((err = snd_cs5535audio_mixer(cs5535au)) < 0) |
351 | goto probefail_out; | 368 | goto probefail_out; |
352 | 369 | ||
@@ -383,6 +400,10 @@ static struct pci_driver driver = { | |||
383 | .id_table = snd_cs5535audio_ids, | 400 | .id_table = snd_cs5535audio_ids, |
384 | .probe = snd_cs5535audio_probe, | 401 | .probe = snd_cs5535audio_probe, |
385 | .remove = __devexit_p(snd_cs5535audio_remove), | 402 | .remove = __devexit_p(snd_cs5535audio_remove), |
403 | #ifdef CONFIG_PM | ||
404 | .suspend = snd_cs5535audio_suspend, | ||
405 | .resume = snd_cs5535audio_resume, | ||
406 | #endif | ||
386 | }; | 407 | }; |
387 | 408 | ||
388 | static int __init alsa_card_cs5535audio_init(void) | 409 | static int __init alsa_card_cs5535audio_init(void) |
diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 5e55a1a1ed65..4fd1f31a6cf9 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h | |||
@@ -74,6 +74,8 @@ | |||
74 | #define PRM_RDY_STS 0x00800000 | 74 | #define PRM_RDY_STS 0x00800000 |
75 | #define ACC_CODEC_CNTL_WR_CMD (~0x80000000) | 75 | #define ACC_CODEC_CNTL_WR_CMD (~0x80000000) |
76 | #define ACC_CODEC_CNTL_RD_CMD 0x80000000 | 76 | #define ACC_CODEC_CNTL_RD_CMD 0x80000000 |
77 | #define ACC_CODEC_CNTL_LNK_SHUTDOWN 0x00040000 | ||
78 | #define ACC_CODEC_CNTL_LNK_WRM_RST 0x00020000 | ||
77 | #define PRD_JMP 0x2000 | 79 | #define PRD_JMP 0x2000 |
78 | #define PRD_EOP 0x4000 | 80 | #define PRD_EOP 0x4000 |
79 | #define PRD_EOT 0x8000 | 81 | #define PRD_EOT 0x8000 |
@@ -88,6 +90,7 @@ struct cs5535audio_dma_ops { | |||
88 | void (*disable_dma)(struct cs5535audio *cs5535au); | 90 | void (*disable_dma)(struct cs5535audio *cs5535au); |
89 | void (*pause_dma)(struct cs5535audio *cs5535au); | 91 | void (*pause_dma)(struct cs5535audio *cs5535au); |
90 | void (*setup_prd)(struct cs5535audio *cs5535au, u32 prd_addr); | 92 | void (*setup_prd)(struct cs5535audio *cs5535au, u32 prd_addr); |
93 | u32 (*read_prd)(struct cs5535audio *cs5535au); | ||
91 | u32 (*read_dma_pntr)(struct cs5535audio *cs5535au); | 94 | u32 (*read_dma_pntr)(struct cs5535audio *cs5535au); |
92 | }; | 95 | }; |
93 | 96 | ||
@@ -103,11 +106,14 @@ struct cs5535audio_dma { | |||
103 | struct snd_pcm_substream *substream; | 106 | struct snd_pcm_substream *substream; |
104 | unsigned int buf_addr, buf_bytes; | 107 | unsigned int buf_addr, buf_bytes; |
105 | unsigned int period_bytes, periods; | 108 | unsigned int period_bytes, periods; |
109 | int suspended; | ||
110 | u32 saved_prd; | ||
106 | }; | 111 | }; |
107 | 112 | ||
108 | struct cs5535audio { | 113 | struct cs5535audio { |
109 | struct snd_card *card; | 114 | struct snd_card *card; |
110 | struct snd_ac97 *ac97; | 115 | struct snd_ac97 *ac97; |
116 | struct snd_pcm *pcm; | ||
111 | int irq; | 117 | int irq; |
112 | struct pci_dev *pci; | 118 | struct pci_dev *pci; |
113 | unsigned long port; | 119 | unsigned long port; |
@@ -117,6 +123,8 @@ struct cs5535audio { | |||
117 | struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; | 123 | struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; |
118 | }; | 124 | }; |
119 | 125 | ||
126 | int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); | ||
127 | int snd_cs5535audio_resume(struct pci_dev *pci); | ||
120 | int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); | 128 | int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); |
121 | 129 | ||
122 | #endif /* __SOUND_CS5535AUDIO_H */ | 130 | #endif /* __SOUND_CS5535AUDIO_H */ |
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 60bb82b2ff47..f0a48693d687 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c | |||
@@ -43,7 +43,8 @@ static struct snd_pcm_hardware snd_cs5535audio_playback = | |||
43 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 43 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
44 | SNDRV_PCM_INFO_MMAP_VALID | | 44 | SNDRV_PCM_INFO_MMAP_VALID | |
45 | SNDRV_PCM_INFO_PAUSE | | 45 | SNDRV_PCM_INFO_PAUSE | |
46 | SNDRV_PCM_INFO_SYNC_START | 46 | SNDRV_PCM_INFO_SYNC_START | |
47 | SNDRV_PCM_INFO_RESUME | ||
47 | ), | 48 | ), |
48 | .formats = ( | 49 | .formats = ( |
49 | SNDRV_PCM_FMTBIT_S16_LE | 50 | SNDRV_PCM_FMTBIT_S16_LE |
@@ -193,6 +194,11 @@ static void cs5535audio_playback_setup_prd(struct cs5535audio *cs5535au, | |||
193 | cs_writel(cs5535au, ACC_BM0_PRD, prd_addr); | 194 | cs_writel(cs5535au, ACC_BM0_PRD, prd_addr); |
194 | } | 195 | } |
195 | 196 | ||
197 | static u32 cs5535audio_playback_read_prd(struct cs5535audio *cs5535au) | ||
198 | { | ||
199 | return cs_readl(cs5535au, ACC_BM0_PRD); | ||
200 | } | ||
201 | |||
196 | static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au) | 202 | static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au) |
197 | { | 203 | { |
198 | return cs_readl(cs5535au, ACC_BM0_PNTR); | 204 | return cs_readl(cs5535au, ACC_BM0_PNTR); |
@@ -219,6 +225,11 @@ static void cs5535audio_capture_setup_prd(struct cs5535audio *cs5535au, | |||
219 | cs_writel(cs5535au, ACC_BM1_PRD, prd_addr); | 225 | cs_writel(cs5535au, ACC_BM1_PRD, prd_addr); |
220 | } | 226 | } |
221 | 227 | ||
228 | static u32 cs5535audio_capture_read_prd(struct cs5535audio *cs5535au) | ||
229 | { | ||
230 | return cs_readl(cs5535au, ACC_BM1_PRD); | ||
231 | } | ||
232 | |||
222 | static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au) | 233 | static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au) |
223 | { | 234 | { |
224 | return cs_readl(cs5535au, ACC_BM1_PNTR); | 235 | return cs_readl(cs5535au, ACC_BM1_PNTR); |
@@ -285,9 +296,17 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd) | |||
285 | case SNDRV_PCM_TRIGGER_START: | 296 | case SNDRV_PCM_TRIGGER_START: |
286 | dma->ops->enable_dma(cs5535au); | 297 | dma->ops->enable_dma(cs5535au); |
287 | break; | 298 | break; |
299 | case SNDRV_PCM_TRIGGER_RESUME: | ||
300 | dma->ops->enable_dma(cs5535au); | ||
301 | dma->suspended = 0; | ||
302 | break; | ||
288 | case SNDRV_PCM_TRIGGER_STOP: | 303 | case SNDRV_PCM_TRIGGER_STOP: |
289 | dma->ops->disable_dma(cs5535au); | 304 | dma->ops->disable_dma(cs5535au); |
290 | break; | 305 | break; |
306 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
307 | dma->ops->disable_dma(cs5535au); | ||
308 | dma->suspended = 1; | ||
309 | break; | ||
291 | default: | 310 | default: |
292 | snd_printk(KERN_ERR "unhandled trigger\n"); | 311 | snd_printk(KERN_ERR "unhandled trigger\n"); |
293 | err = -EINVAL; | 312 | err = -EINVAL; |
@@ -375,6 +394,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { | |||
375 | .enable_dma = cs5535audio_playback_enable_dma, | 394 | .enable_dma = cs5535audio_playback_enable_dma, |
376 | .disable_dma = cs5535audio_playback_disable_dma, | 395 | .disable_dma = cs5535audio_playback_disable_dma, |
377 | .setup_prd = cs5535audio_playback_setup_prd, | 396 | .setup_prd = cs5535audio_playback_setup_prd, |
397 | .read_prd = cs5535audio_playback_read_prd, | ||
378 | .pause_dma = cs5535audio_playback_pause_dma, | 398 | .pause_dma = cs5535audio_playback_pause_dma, |
379 | .read_dma_pntr = cs5535audio_playback_read_dma_pntr, | 399 | .read_dma_pntr = cs5535audio_playback_read_dma_pntr, |
380 | }; | 400 | }; |
@@ -384,6 +404,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { | |||
384 | .enable_dma = cs5535audio_capture_enable_dma, | 404 | .enable_dma = cs5535audio_capture_enable_dma, |
385 | .disable_dma = cs5535audio_capture_disable_dma, | 405 | .disable_dma = cs5535audio_capture_disable_dma, |
386 | .setup_prd = cs5535audio_capture_setup_prd, | 406 | .setup_prd = cs5535audio_capture_setup_prd, |
407 | .read_prd = cs5535audio_capture_read_prd, | ||
387 | .pause_dma = cs5535audio_capture_pause_dma, | 408 | .pause_dma = cs5535audio_capture_pause_dma, |
388 | .read_dma_pntr = cs5535audio_capture_read_dma_pntr, | 409 | .read_dma_pntr = cs5535audio_capture_read_dma_pntr, |
389 | }; | 410 | }; |
@@ -413,6 +434,7 @@ int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au) | |||
413 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 434 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
414 | snd_dma_pci_data(cs5535au->pci), | 435 | snd_dma_pci_data(cs5535au->pci), |
415 | 64*1024, 128*1024); | 436 | 64*1024, 128*1024); |
437 | cs5535au->pcm = pcm; | ||
416 | 438 | ||
417 | return 0; | 439 | return 0; |
418 | } | 440 | } |
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c new file mode 100644 index 000000000000..aad0e69db9c1 --- /dev/null +++ b/sound/pci/cs5535audio/cs5535audio_pm.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Power management for audio on multifunction CS5535 companion device | ||
3 | * Copyright (C) Jaya Kumar | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/control.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/asoundef.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/ac97_codec.h> | ||
32 | #include "cs5535audio.h" | ||
33 | |||
34 | static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au) | ||
35 | { | ||
36 | /* | ||
37 | we depend on snd_ac97_suspend to tell the | ||
38 | AC97 codec to shutdown. the amd spec suggests | ||
39 | that the LNK_SHUTDOWN be done at the same time | ||
40 | that the codec power-down is issued. instead, | ||
41 | we do it just after rather than at the same | ||
42 | time. excluding codec specific build_ops->suspend | ||
43 | ac97 powerdown hits: | ||
44 | 0x8000 EAPD | ||
45 | 0x4000 Headphone amplifier | ||
46 | 0x0300 ADC & DAC | ||
47 | 0x0400 Analog Mixer powerdown (Vref on) | ||
48 | I am not sure if this is the best that we can do. | ||
49 | The remainder to be investigated are: | ||
50 | - analog mixer (vref off) 0x0800 | ||
51 | - AC-link powerdown 0x1000 | ||
52 | - codec internal clock 0x2000 | ||
53 | */ | ||
54 | |||
55 | /* set LNK_SHUTDOWN to shutdown AC link */ | ||
56 | cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_SHUTDOWN); | ||
57 | |||
58 | } | ||
59 | |||
60 | int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state) | ||
61 | { | ||
62 | struct snd_card *card = pci_get_drvdata(pci); | ||
63 | struct cs5535audio *cs5535au = card->private_data; | ||
64 | int i; | ||
65 | |||
66 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
67 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { | ||
68 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; | ||
69 | if (dma && dma->substream && !dma->suspended) | ||
70 | dma->saved_prd = dma->ops->read_prd(cs5535au); | ||
71 | } | ||
72 | snd_pcm_suspend_all(cs5535au->pcm); | ||
73 | snd_ac97_suspend(cs5535au->ac97); | ||
74 | /* save important regs, then disable aclink in hw */ | ||
75 | snd_cs5535audio_stop_hardware(cs5535au); | ||
76 | pci_disable_device(pci); | ||
77 | pci_save_state(pci); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int snd_cs5535audio_resume(struct pci_dev *pci) | ||
83 | { | ||
84 | struct snd_card *card = pci_get_drvdata(pci); | ||
85 | struct cs5535audio *cs5535au = card->private_data; | ||
86 | u32 tmp; | ||
87 | int timeout; | ||
88 | int i; | ||
89 | |||
90 | pci_restore_state(pci); | ||
91 | pci_enable_device(pci); | ||
92 | pci_set_master(pci); | ||
93 | |||
94 | /* set LNK_WRM_RST to reset AC link */ | ||
95 | cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST); | ||
96 | |||
97 | timeout = 50; | ||
98 | do { | ||
99 | tmp = cs_readl(cs5535au, ACC_CODEC_STATUS); | ||
100 | if (tmp & PRM_RDY_STS) | ||
101 | break; | ||
102 | udelay(1); | ||
103 | } while (--timeout); | ||
104 | |||
105 | if (!timeout) | ||
106 | snd_printk(KERN_ERR "Failure getting AC Link ready\n"); | ||
107 | |||
108 | /* we depend on ac97 to perform the codec power up */ | ||
109 | snd_ac97_resume(cs5535au->ac97); | ||
110 | /* set up rate regs, dma. actual initiation is done in trig */ | ||
111 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { | ||
112 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; | ||
113 | if (dma && dma->substream && dma->suspended) { | ||
114 | dma->substream->ops->prepare(dma->substream); | ||
115 | dma->ops->setup_prd(cs5535au, dma->saved_prd); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||