]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From 2c5dd6425e72a6e97d9fb9fee9910a58f02d77df Mon Sep 17 00:00:00 2001 |
2 | From: Takashi Iwai <tiwai@suse.de> | |
3 | Subject: ALSA: ca0106 - Add power-amangement support | |
4 | Patch-mainline: | |
5 | References: bnc#447624 | |
6 | ||
7 | Added the missing PM support for snd-ca0106 driver. | |
8 | ||
9 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
10 | ||
11 | --- | |
12 | ||
13 | --- | |
14 | sound/pci/ca0106/ca0106.h | 15 + | |
15 | sound/pci/ca0106/ca0106_main.c | 532 +++++++++++++++++++++++----------------- | |
16 | sound/pci/ca0106/ca0106_mixer.c | 182 +++++++++---- | |
17 | 3 files changed, 457 insertions(+), 272 deletions(-) | |
18 | ||
19 | --- a/sound/pci/ca0106/ca0106.h | |
20 | +++ b/sound/pci/ca0106/ca0106.h | |
21 | @@ -686,7 +686,7 @@ struct snd_ca0106 { | |
22 | spinlock_t emu_lock; | |
23 | ||
24 | struct snd_ac97 *ac97; | |
25 | - struct snd_pcm *pcm; | |
26 | + struct snd_pcm *pcm[4]; | |
27 | ||
28 | struct snd_ca0106_channel playback_channels[4]; | |
29 | struct snd_ca0106_channel capture_channels[4]; | |
30 | @@ -703,6 +703,11 @@ struct snd_ca0106 { | |
31 | struct snd_ca_midi midi2; | |
32 | ||
33 | u16 spi_dac_reg[16]; | |
34 | + | |
35 | +#ifdef CONFIG_PM | |
36 | +#define NUM_SAVED_VOLUMES 9 | |
37 | + unsigned int saved_vol[NUM_SAVED_VOLUMES]; | |
38 | +#endif | |
39 | }; | |
40 | ||
41 | int snd_ca0106_mixer(struct snd_ca0106 *emu); | |
42 | @@ -721,3 +726,11 @@ int snd_ca0106_i2c_write(struct snd_ca01 | |
43 | ||
44 | int snd_ca0106_spi_write(struct snd_ca0106 * emu, | |
45 | unsigned int data); | |
46 | + | |
47 | +#ifdef CONFIG_PM | |
48 | +void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip); | |
49 | +void snd_ca0106_mixer_resume(struct snd_ca0106 *chip); | |
50 | +#else | |
51 | +#define snd_ca0106_mixer_suspend(chip) do { } while (0) | |
52 | +#define snd_ca0106_mixer_resume(chip) do { } while (0) | |
53 | +#endif | |
54 | --- a/sound/pci/ca0106/ca0106_main.c | |
55 | +++ b/sound/pci/ca0106/ca0106_main.c | |
56 | @@ -848,15 +848,18 @@ static int snd_ca0106_pcm_trigger_playba | |
57 | struct snd_pcm_substream *s; | |
58 | u32 basic = 0; | |
59 | u32 extended = 0; | |
60 | - int running=0; | |
61 | + u32 bits; | |
62 | + int running = 0; | |
63 | ||
64 | switch (cmd) { | |
65 | case SNDRV_PCM_TRIGGER_START: | |
66 | - running=1; | |
67 | + case SNDRV_PCM_TRIGGER_RESUME: | |
68 | + running = 1; | |
69 | break; | |
70 | case SNDRV_PCM_TRIGGER_STOP: | |
71 | + case SNDRV_PCM_TRIGGER_SUSPEND: | |
72 | default: | |
73 | - running=0; | |
74 | + running = 0; | |
75 | break; | |
76 | } | |
77 | snd_pcm_group_for_each_entry(s, substream) { | |
78 | @@ -866,22 +869,32 @@ static int snd_ca0106_pcm_trigger_playba | |
79 | runtime = s->runtime; | |
80 | epcm = runtime->private_data; | |
81 | channel = epcm->channel_id; | |
82 | - //snd_printk("channel=%d\n",channel); | |
83 | + /* snd_printk("channel=%d\n",channel); */ | |
84 | epcm->running = running; | |
85 | - basic |= (0x1<<channel); | |
86 | - extended |= (0x10<<channel); | |
87 | + basic |= (0x1 << channel); | |
88 | + extended |= (0x10 << channel); | |
89 | snd_pcm_trigger_done(s, substream); | |
90 | } | |
91 | - //snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); | |
92 | + /* snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); */ | |
93 | ||
94 | switch (cmd) { | |
95 | case SNDRV_PCM_TRIGGER_START: | |
96 | - snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended)); | |
97 | - snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic)); | |
98 | + case SNDRV_PCM_TRIGGER_RESUME: | |
99 | + bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); | |
100 | + bits |= extended; | |
101 | + snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); | |
102 | + bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); | |
103 | + bits |= basic; | |
104 | + snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); | |
105 | break; | |
106 | case SNDRV_PCM_TRIGGER_STOP: | |
107 | - snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); | |
108 | - snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended)); | |
109 | + case SNDRV_PCM_TRIGGER_SUSPEND: | |
110 | + bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); | |
111 | + bits &= ~basic; | |
112 | + snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); | |
113 | + bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); | |
114 | + bits &= ~extended; | |
115 | + snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); | |
116 | break; | |
117 | default: | |
118 | result = -EINVAL; | |
119 | @@ -1104,21 +1117,13 @@ static int snd_ca0106_ac97(struct snd_ca | |
120 | return snd_ac97_mixer(pbus, &ac97, &chip->ac97); | |
121 | } | |
122 | ||
123 | +static void ca0106_stop_chip(struct snd_ca0106 *chip); | |
124 | + | |
125 | static int snd_ca0106_free(struct snd_ca0106 *chip) | |
126 | { | |
127 | - if (chip->res_port != NULL) { /* avoid access to already used hardware */ | |
128 | - // disable interrupts | |
129 | - snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); | |
130 | - outl(0, chip->port + INTE); | |
131 | - snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); | |
132 | - udelay(1000); | |
133 | - // disable audio | |
134 | - //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); | |
135 | - outl(0, chip->port + HCFG); | |
136 | - /* FIXME: We need to stop and DMA transfers here. | |
137 | - * But as I am not sure how yet, we cannot from the dma pages. | |
138 | - * So we can fix: snd-malloc: Memory leak? pages not freed = 8 | |
139 | - */ | |
140 | + if (chip->res_port != NULL) { | |
141 | + /* avoid access to already used hardware */ | |
142 | + ca0106_stop_chip(chip); | |
143 | } | |
144 | if (chip->irq >= 0) | |
145 | free_irq(chip->irq, chip); | |
146 | @@ -1204,15 +1209,14 @@ static irqreturn_t snd_ca0106_interrupt( | |
147 | return IRQ_HANDLED; | |
148 | } | |
149 | ||
150 | -static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) | |
151 | +static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) | |
152 | { | |
153 | struct snd_pcm *pcm; | |
154 | struct snd_pcm_substream *substream; | |
155 | int err; | |
156 | ||
157 | - if (rpcm) | |
158 | - *rpcm = NULL; | |
159 | - if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) | |
160 | + err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); | |
161 | + if (err < 0) | |
162 | return err; | |
163 | ||
164 | pcm->private_data = emu; | |
165 | @@ -1239,7 +1243,6 @@ static int __devinit snd_ca0106_pcm(stru | |
166 | pcm->info_flags = 0; | |
167 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | |
168 | strcpy(pcm->name, "CA0106"); | |
169 | - emu->pcm = pcm; | |
170 | ||
171 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | |
172 | substream; | |
173 | @@ -1261,8 +1264,7 @@ static int __devinit snd_ca0106_pcm(stru | |
174 | return err; | |
175 | } | |
176 | ||
177 | - if (rpcm) | |
178 | - *rpcm = pcm; | |
179 | + emu->pcm[device] = pcm; | |
180 | ||
181 | return 0; | |
182 | } | |
183 | @@ -1302,89 +1304,10 @@ static unsigned int i2c_adc_init[][2] = | |
184 | { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ | |
185 | }; | |
186 | ||
187 | -static int __devinit snd_ca0106_create(int dev, struct snd_card *card, | |
188 | - struct pci_dev *pci, | |
189 | - struct snd_ca0106 **rchip) | |
190 | +static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |
191 | { | |
192 | - struct snd_ca0106 *chip; | |
193 | - struct snd_ca0106_details *c; | |
194 | - int err; | |
195 | int ch; | |
196 | - static struct snd_device_ops ops = { | |
197 | - .dev_free = snd_ca0106_dev_free, | |
198 | - }; | |
199 | - | |
200 | - *rchip = NULL; | |
201 | - | |
202 | - if ((err = pci_enable_device(pci)) < 0) | |
203 | - return err; | |
204 | - if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || | |
205 | - pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { | |
206 | - printk(KERN_ERR "error to set 32bit mask DMA\n"); | |
207 | - pci_disable_device(pci); | |
208 | - return -ENXIO; | |
209 | - } | |
210 | - | |
211 | - chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
212 | - if (chip == NULL) { | |
213 | - pci_disable_device(pci); | |
214 | - return -ENOMEM; | |
215 | - } | |
216 | - | |
217 | - chip->card = card; | |
218 | - chip->pci = pci; | |
219 | - chip->irq = -1; | |
220 | - | |
221 | - spin_lock_init(&chip->emu_lock); | |
222 | - | |
223 | - chip->port = pci_resource_start(pci, 0); | |
224 | - if ((chip->res_port = request_region(chip->port, 0x20, | |
225 | - "snd_ca0106")) == NULL) { | |
226 | - snd_ca0106_free(chip); | |
227 | - printk(KERN_ERR "cannot allocate the port\n"); | |
228 | - return -EBUSY; | |
229 | - } | |
230 | - | |
231 | - if (request_irq(pci->irq, snd_ca0106_interrupt, | |
232 | - IRQF_SHARED, "snd_ca0106", chip)) { | |
233 | - snd_ca0106_free(chip); | |
234 | - printk(KERN_ERR "cannot grab irq\n"); | |
235 | - return -EBUSY; | |
236 | - } | |
237 | - chip->irq = pci->irq; | |
238 | - | |
239 | - /* This stores the periods table. */ | |
240 | - if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { | |
241 | - snd_ca0106_free(chip); | |
242 | - return -ENOMEM; | |
243 | - } | |
244 | - | |
245 | - pci_set_master(pci); | |
246 | - /* read serial */ | |
247 | - pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); | |
248 | - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); | |
249 | -#if 1 | |
250 | - printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, | |
251 | - pci->revision, chip->serial); | |
252 | -#endif | |
253 | - strcpy(card->driver, "CA0106"); | |
254 | - strcpy(card->shortname, "CA0106"); | |
255 | - | |
256 | - for (c = ca0106_chip_details; c->serial; c++) { | |
257 | - if (subsystem[dev]) { | |
258 | - if (c->serial == subsystem[dev]) | |
259 | - break; | |
260 | - } else if (c->serial == chip->serial) | |
261 | - break; | |
262 | - } | |
263 | - chip->details = c; | |
264 | - if (subsystem[dev]) { | |
265 | - printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", | |
266 | - c->name, chip->serial, subsystem[dev]); | |
267 | - } | |
268 | - | |
269 | - sprintf(card->longname, "%s at 0x%lx irq %i", | |
270 | - c->name, chip->port, chip->irq); | |
271 | + unsigned int def_bits; | |
272 | ||
273 | outl(0, chip->port + INTE); | |
274 | ||
275 | @@ -1402,31 +1325,22 @@ static int __devinit snd_ca0106_create(i | |
276 | * AN = 0 (Audio data) | |
277 | * P = 0 (Consumer) | |
278 | */ | |
279 | - snd_ca0106_ptr_write(chip, SPCS0, 0, | |
280 | - chip->spdif_bits[0] = | |
281 | - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | |
282 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | |
283 | - SPCS_GENERATIONSTATUS | 0x00001200 | | |
284 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | |
285 | + def_bits = | |
286 | + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | |
287 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | |
288 | + SPCS_GENERATIONSTATUS | 0x00001200 | | |
289 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; | |
290 | + if (!resume) { | |
291 | + chip->spdif_bits[0] = def_bits; | |
292 | + chip->spdif_bits[1] = def_bits; | |
293 | + chip->spdif_bits[2] = def_bits; | |
294 | + chip->spdif_bits[3] = def_bits; | |
295 | + } | |
296 | /* Only SPCS1 has been tested */ | |
297 | - snd_ca0106_ptr_write(chip, SPCS1, 0, | |
298 | - chip->spdif_bits[1] = | |
299 | - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | |
300 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | |
301 | - SPCS_GENERATIONSTATUS | 0x00001200 | | |
302 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | |
303 | - snd_ca0106_ptr_write(chip, SPCS2, 0, | |
304 | - chip->spdif_bits[2] = | |
305 | - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | |
306 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | |
307 | - SPCS_GENERATIONSTATUS | 0x00001200 | | |
308 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | |
309 | - snd_ca0106_ptr_write(chip, SPCS3, 0, | |
310 | - chip->spdif_bits[3] = | |
311 | - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | |
312 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | |
313 | - SPCS_GENERATIONSTATUS | 0x00001200 | | |
314 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | |
315 | + snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); | |
316 | + snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); | |
317 | + snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); | |
318 | + snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); | |
319 | ||
320 | snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); | |
321 | snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); | |
322 | @@ -1434,92 +1348,124 @@ static int __devinit snd_ca0106_create(i | |
323 | /* Write 0x8000 to AC97_REC_GAIN to mute it. */ | |
324 | outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); | |
325 | outw(0x8000, chip->port + AC97DATA); | |
326 | -#if 0 | |
327 | +#if 0 /* FIXME: what are these? */ | |
328 | snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); | |
329 | snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); | |
330 | snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); | |
331 | snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); | |
332 | #endif | |
333 | ||
334 | - //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ | |
335 | + /* OSS drivers set this. */ | |
336 | + /* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */ | |
337 | + | |
338 | /* Analog or Digital output */ | |
339 | snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); | |
340 | - snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ | |
341 | + /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. | |
342 | + * Use 0x000f0000 for surround71 | |
343 | + */ | |
344 | + snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); | |
345 | + | |
346 | chip->spdif_enable = 0; /* Set digital SPDIF output off */ | |
347 | - //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ | |
348 | - //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ | |
349 | + /*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */ | |
350 | + /*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */ | |
351 | + | |
352 | + /* goes to 0x40c80000 when doing SPDIF IN/OUT */ | |
353 | + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); | |
354 | + /* (Mute) CAPTURE feedback into PLAYBACK volume. | |
355 | + * Only lower 16 bits matter. | |
356 | + */ | |
357 | + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); | |
358 | + /* SPDIF IN Volume */ | |
359 | + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); | |
360 | + /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ | |
361 | + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); | |
362 | ||
363 | - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ | |
364 | - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ | |
365 | - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ | |
366 | - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ | |
367 | snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); | |
368 | snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); | |
369 | snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); | |
370 | snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); | |
371 | - for(ch = 0; ch < 4; ch++) { | |
372 | - snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ | |
373 | + | |
374 | + for (ch = 0; ch < 4; ch++) { | |
375 | + /* Only high 16 bits matter */ | |
376 | + snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); | |
377 | snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); | |
378 | - //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ | |
379 | - //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ | |
380 | - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ | |
381 | - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ | |
382 | +#if 0 /* Mute */ | |
383 | + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); | |
384 | + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); | |
385 | + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); | |
386 | + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); | |
387 | +#endif | |
388 | } | |
389 | if (chip->details->i2c_adc == 1) { | |
390 | /* Select MIC, Line in, TAD in, AUX in */ | |
391 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); | |
392 | /* Default to CAPTURE_SOURCE to i2s in */ | |
393 | - chip->capture_source = 3; | |
394 | + if (!resume) | |
395 | + chip->capture_source = 3; | |
396 | } else if (chip->details->ac97 == 1) { | |
397 | /* Default to AC97 in */ | |
398 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); | |
399 | /* Default to CAPTURE_SOURCE to AC97 in */ | |
400 | - chip->capture_source = 4; | |
401 | + if (!resume) | |
402 | + chip->capture_source = 4; | |
403 | } else { | |
404 | /* Select MIC, Line in, TAD in, AUX in */ | |
405 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); | |
406 | /* Default to Set CAPTURE_SOURCE to i2s in */ | |
407 | - chip->capture_source = 3; | |
408 | + if (!resume) | |
409 | + chip->capture_source = 3; | |
410 | } | |
411 | ||
412 | - if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ | |
413 | - /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | |
414 | + if (chip->details->gpio_type == 2) { | |
415 | + /* The SB0438 use GPIO differently. */ | |
416 | + /* FIXME: Still need to find out what the other GPIO bits do. | |
417 | + * E.g. For digital spdif out. | |
418 | + */ | |
419 | outl(0x0, chip->port+GPIO); | |
420 | - //outl(0x00f0e000, chip->port+GPIO); /* Analog */ | |
421 | + /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ | |
422 | outl(0x005f5301, chip->port+GPIO); /* Analog */ | |
423 | - } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ | |
424 | - /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | |
425 | + } else if (chip->details->gpio_type == 1) { | |
426 | + /* The SB0410 and SB0413 use GPIO differently. */ | |
427 | + /* FIXME: Still need to find out what the other GPIO bits do. | |
428 | + * E.g. For digital spdif out. | |
429 | + */ | |
430 | outl(0x0, chip->port+GPIO); | |
431 | - //outl(0x00f0e000, chip->port+GPIO); /* Analog */ | |
432 | + /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ | |
433 | outl(0x005f5301, chip->port+GPIO); /* Analog */ | |
434 | } else { | |
435 | outl(0x0, chip->port+GPIO); | |
436 | outl(0x005f03a3, chip->port+GPIO); /* Analog */ | |
437 | - //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ | |
438 | + /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ | |
439 | } | |
440 | snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ | |
441 | ||
442 | - //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); | |
443 | - //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ | |
444 | - //outl(0x00000009, chip->port+HCFG); | |
445 | - outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ | |
446 | + /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ | |
447 | + /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ | |
448 | + /* outl(0x00001409, chip->port+HCFG); */ | |
449 | + /* outl(0x00000009, chip->port+HCFG); */ | |
450 | + /* AC97 2.0, Enable outputs. */ | |
451 | + outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); | |
452 | ||
453 | - if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ | |
454 | + if (chip->details->i2c_adc == 1) { | |
455 | + /* The SB0410 and SB0413 use I2C to control ADC. */ | |
456 | int size, n; | |
457 | ||
458 | size = ARRAY_SIZE(i2c_adc_init); | |
459 | - //snd_printk("I2C:array size=0x%x\n", size); | |
460 | - for (n=0; n < size; n++) { | |
461 | - snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); | |
462 | - } | |
463 | - for (n=0; n < 4; n++) { | |
464 | - chip->i2c_capture_volume[n][0]= 0xcf; | |
465 | - chip->i2c_capture_volume[n][1]= 0xcf; | |
466 | + /* snd_printk("I2C:array size=0x%x\n", size); */ | |
467 | + for (n = 0; n < size; n++) | |
468 | + snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], | |
469 | + i2c_adc_init[n][1]); | |
470 | + for (n = 0; n < 4; n++) { | |
471 | + chip->i2c_capture_volume[n][0] = 0xcf; | |
472 | + chip->i2c_capture_volume[n][1] = 0xcf; | |
473 | } | |
474 | - chip->i2c_capture_source=2; /* Line in */ | |
475 | - //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ | |
476 | + chip->i2c_capture_source = 2; /* Line in */ | |
477 | + /* Enable Line-in capture. MIC in currently untested. */ | |
478 | + /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ | |
479 | } | |
480 | - if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ | |
481 | + | |
482 | + if (chip->details->spi_dac == 1) { | |
483 | + /* The SB0570 use SPI to control DAC. */ | |
484 | int size, n; | |
485 | ||
486 | size = ARRAY_SIZE(spi_dac_init); | |
487 | @@ -1531,9 +1477,112 @@ static int __devinit snd_ca0106_create(i | |
488 | chip->spi_dac_reg[reg] = spi_dac_init[n]; | |
489 | } | |
490 | } | |
491 | +} | |
492 | + | |
493 | +static void ca0106_stop_chip(struct snd_ca0106 *chip) | |
494 | +{ | |
495 | + /* disable interrupts */ | |
496 | + snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); | |
497 | + outl(0, chip->port + INTE); | |
498 | + snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); | |
499 | + udelay(1000); | |
500 | + /* disable audio */ | |
501 | + /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ | |
502 | + outl(0, chip->port + HCFG); | |
503 | + /* FIXME: We need to stop and DMA transfers here. | |
504 | + * But as I am not sure how yet, we cannot from the dma pages. | |
505 | + * So we can fix: snd-malloc: Memory leak? pages not freed = 8 | |
506 | + */ | |
507 | +} | |
508 | ||
509 | - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, | |
510 | - chip, &ops)) < 0) { | |
511 | +static int __devinit snd_ca0106_create(int dev, struct snd_card *card, | |
512 | + struct pci_dev *pci, | |
513 | + struct snd_ca0106 **rchip) | |
514 | +{ | |
515 | + struct snd_ca0106 *chip; | |
516 | + struct snd_ca0106_details *c; | |
517 | + int err; | |
518 | + static struct snd_device_ops ops = { | |
519 | + .dev_free = snd_ca0106_dev_free, | |
520 | + }; | |
521 | + | |
522 | + *rchip = NULL; | |
523 | + | |
524 | + err = pci_enable_device(pci); | |
525 | + if (err < 0) | |
526 | + return err; | |
527 | + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || | |
528 | + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { | |
529 | + printk(KERN_ERR "error to set 32bit mask DMA\n"); | |
530 | + pci_disable_device(pci); | |
531 | + return -ENXIO; | |
532 | + } | |
533 | + | |
534 | + chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
535 | + if (chip == NULL) { | |
536 | + pci_disable_device(pci); | |
537 | + return -ENOMEM; | |
538 | + } | |
539 | + | |
540 | + chip->card = card; | |
541 | + chip->pci = pci; | |
542 | + chip->irq = -1; | |
543 | + | |
544 | + spin_lock_init(&chip->emu_lock); | |
545 | + | |
546 | + chip->port = pci_resource_start(pci, 0); | |
547 | + chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); | |
548 | + if (!chip->res_port) { | |
549 | + snd_ca0106_free(chip); | |
550 | + printk(KERN_ERR "cannot allocate the port\n"); | |
551 | + return -EBUSY; | |
552 | + } | |
553 | + | |
554 | + if (request_irq(pci->irq, snd_ca0106_interrupt, | |
555 | + IRQF_SHARED, "snd_ca0106", chip)) { | |
556 | + snd_ca0106_free(chip); | |
557 | + printk(KERN_ERR "cannot grab irq\n"); | |
558 | + return -EBUSY; | |
559 | + } | |
560 | + chip->irq = pci->irq; | |
561 | + | |
562 | + /* This stores the periods table. */ | |
563 | + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | |
564 | + 1024, &chip->buffer) < 0) { | |
565 | + snd_ca0106_free(chip); | |
566 | + return -ENOMEM; | |
567 | + } | |
568 | + | |
569 | + pci_set_master(pci); | |
570 | + /* read serial */ | |
571 | + pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); | |
572 | + pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); | |
573 | + printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", | |
574 | + chip->model, pci->revision, chip->serial); | |
575 | + strcpy(card->driver, "CA0106"); | |
576 | + strcpy(card->shortname, "CA0106"); | |
577 | + | |
578 | + for (c = ca0106_chip_details; c->serial; c++) { | |
579 | + if (subsystem[dev]) { | |
580 | + if (c->serial == subsystem[dev]) | |
581 | + break; | |
582 | + } else if (c->serial == chip->serial) | |
583 | + break; | |
584 | + } | |
585 | + chip->details = c; | |
586 | + if (subsystem[dev]) { | |
587 | + printk(KERN_INFO "snd-ca0106: Sound card name=%s, " | |
588 | + "subsystem=0x%x. Forced to subsystem=0x%x\n", | |
589 | + c->name, chip->serial, subsystem[dev]); | |
590 | + } | |
591 | + | |
592 | + sprintf(card->longname, "%s at 0x%lx irq %i", | |
593 | + c->name, chip->port, chip->irq); | |
594 | + | |
595 | + ca0106_init_chip(chip, 0); | |
596 | + | |
597 | + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | |
598 | + if (err < 0) { | |
599 | snd_ca0106_free(chip); | |
600 | return err; | |
601 | } | |
602 | @@ -1630,7 +1679,7 @@ static int __devinit snd_ca0106_probe(st | |
603 | static int dev; | |
604 | struct snd_card *card; | |
605 | struct snd_ca0106 *chip; | |
606 | - int err; | |
607 | + int i, err; | |
608 | ||
609 | if (dev >= SNDRV_CARDS) | |
610 | return -ENODEV; | |
611 | @@ -1643,44 +1692,31 @@ static int __devinit snd_ca0106_probe(st | |
612 | if (card == NULL) | |
613 | return -ENOMEM; | |
614 | ||
615 | - if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { | |
616 | - snd_card_free(card); | |
617 | - return err; | |
618 | - } | |
619 | - | |
620 | - if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { | |
621 | - snd_card_free(card); | |
622 | - return err; | |
623 | - } | |
624 | - if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { | |
625 | - snd_card_free(card); | |
626 | - return err; | |
627 | - } | |
628 | - if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { | |
629 | - snd_card_free(card); | |
630 | - return err; | |
631 | - } | |
632 | - if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { | |
633 | - snd_card_free(card); | |
634 | - return err; | |
635 | - } | |
636 | - if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ | |
637 | - if ((err = snd_ca0106_ac97(chip)) < 0) { | |
638 | - snd_card_free(card); | |
639 | - return err; | |
640 | - } | |
641 | - } | |
642 | - if ((err = snd_ca0106_mixer(chip)) < 0) { | |
643 | - snd_card_free(card); | |
644 | - return err; | |
645 | - } | |
646 | + err = snd_ca0106_create(dev, card, pci, &chip); | |
647 | + if (err < 0) | |
648 | + goto error; | |
649 | + card->private_data = chip; | |
650 | + | |
651 | + for (i = 0; i < 4; i++) { | |
652 | + err = snd_ca0106_pcm(chip, i); | |
653 | + if (err < 0) | |
654 | + goto error; | |
655 | + } | |
656 | + | |
657 | + if (chip->details->ac97 == 1) { | |
658 | + /* The SB0410 and SB0413 do not have an AC97 chip. */ | |
659 | + err = snd_ca0106_ac97(chip); | |
660 | + if (err < 0) | |
661 | + goto error; | |
662 | + } | |
663 | + err = snd_ca0106_mixer(chip); | |
664 | + if (err < 0) | |
665 | + goto error; | |
666 | ||
667 | snd_printdd("ca0106: probe for MIDI channel A ..."); | |
668 | - if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { | |
669 | - snd_card_free(card); | |
670 | - snd_printdd(" failed, err=0x%x\n",err); | |
671 | - return err; | |
672 | - } | |
673 | + err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); | |
674 | + if (err < 0) | |
675 | + goto error; | |
676 | snd_printdd(" done.\n"); | |
677 | ||
678 | #ifdef CONFIG_PROC_FS | |
679 | @@ -1689,14 +1725,17 @@ static int __devinit snd_ca0106_probe(st | |
680 | ||
681 | snd_card_set_dev(card, &pci->dev); | |
682 | ||
683 | - if ((err = snd_card_register(card)) < 0) { | |
684 | - snd_card_free(card); | |
685 | - return err; | |
686 | - } | |
687 | + err = snd_card_register(card); | |
688 | + if (err < 0) | |
689 | + goto error; | |
690 | ||
691 | pci_set_drvdata(pci, card); | |
692 | dev++; | |
693 | return 0; | |
694 | + | |
695 | + error: | |
696 | + snd_card_free(card); | |
697 | + return err; | |
698 | } | |
699 | ||
700 | static void __devexit snd_ca0106_remove(struct pci_dev *pci) | |
701 | @@ -1705,6 +1744,59 @@ static void __devexit snd_ca0106_remove( | |
702 | pci_set_drvdata(pci, NULL); | |
703 | } | |
704 | ||
705 | +#ifdef CONFIG_PM | |
706 | +static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) | |
707 | +{ | |
708 | + struct snd_card *card = pci_get_drvdata(pci); | |
709 | + struct snd_ca0106 *chip = card->private_data; | |
710 | + int i; | |
711 | + | |
712 | + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | |
713 | + for (i = 0; i < 4; i++) | |
714 | + snd_pcm_suspend_all(chip->pcm[i]); | |
715 | + if (chip->details->ac97) | |
716 | + snd_ac97_suspend(chip->ac97); | |
717 | + snd_ca0106_mixer_suspend(chip); | |
718 | + | |
719 | + ca0106_stop_chip(chip); | |
720 | + | |
721 | + pci_disable_device(pci); | |
722 | + pci_save_state(pci); | |
723 | + pci_set_power_state(pci, pci_choose_state(pci, state)); | |
724 | + return 0; | |
725 | +} | |
726 | + | |
727 | +static int snd_ca0106_resume(struct pci_dev *pci) | |
728 | +{ | |
729 | + struct snd_card *card = pci_get_drvdata(pci); | |
730 | + struct snd_ca0106 *chip = card->private_data; | |
731 | + int i; | |
732 | + | |
733 | + pci_set_power_state(pci, PCI_D0); | |
734 | + pci_restore_state(pci); | |
735 | + | |
736 | + if (pci_enable_device(pci) < 0) { | |
737 | + snd_card_disconnect(card); | |
738 | + return -EIO; | |
739 | + } | |
740 | + | |
741 | + pci_set_master(pci); | |
742 | + | |
743 | + ca0106_init_chip(chip, 1); | |
744 | + | |
745 | + if (chip->details->ac97) | |
746 | + snd_ac97_resume(chip->ac97); | |
747 | + snd_ca0106_mixer_resume(chip); | |
748 | + if (chip->details->spi_dac) { | |
749 | + for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) | |
750 | + snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]); | |
751 | + } | |
752 | + | |
753 | + snd_power_change_state(card, SNDRV_CTL_POWER_D0); | |
754 | + return 0; | |
755 | +} | |
756 | +#endif | |
757 | + | |
758 | // PCI IDs | |
759 | static struct pci_device_id snd_ca0106_ids[] = { | |
760 | { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ | |
761 | @@ -1718,6 +1810,8 @@ static struct pci_driver driver = { | |
762 | .id_table = snd_ca0106_ids, | |
763 | .probe = snd_ca0106_probe, | |
764 | .remove = __devexit_p(snd_ca0106_remove), | |
765 | + .suspend = snd_ca0106_suspend, | |
766 | + .resume = snd_ca0106_resume, | |
767 | }; | |
768 | ||
769 | // initialization of the module | |
770 | --- a/sound/pci/ca0106/ca0106_mixer.c | |
771 | +++ b/sound/pci/ca0106/ca0106_mixer.c | |
772 | @@ -75,6 +75,84 @@ | |
773 | ||
774 | #include "ca0106.h" | |
775 | ||
776 | +static void ca0106_spdif_enable(struct snd_ca0106 *emu) | |
777 | +{ | |
778 | + unsigned int val; | |
779 | + | |
780 | + if (emu->spdif_enable) { | |
781 | + /* Digital */ | |
782 | + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | |
783 | + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); | |
784 | + val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; | |
785 | + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); | |
786 | + val = inl(emu->port + GPIO) & ~0x101; | |
787 | + outl(val, emu->port + GPIO); | |
788 | + | |
789 | + } else { | |
790 | + /* Analog */ | |
791 | + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | |
792 | + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); | |
793 | + val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; | |
794 | + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); | |
795 | + val = inl(emu->port + GPIO) | 0x101; | |
796 | + outl(val, emu->port + GPIO); | |
797 | + } | |
798 | +} | |
799 | + | |
800 | +static void ca0106_set_capture_source(struct snd_ca0106 *emu) | |
801 | +{ | |
802 | + unsigned int val = emu->capture_source; | |
803 | + unsigned int source, mask; | |
804 | + source = (val << 28) | (val << 24) | (val << 20) | (val << 16); | |
805 | + mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; | |
806 | + snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); | |
807 | +} | |
808 | + | |
809 | +static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu, | |
810 | + unsigned int val, int force) | |
811 | +{ | |
812 | + unsigned int ngain, ogain; | |
813 | + u32 source; | |
814 | + | |
815 | + snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | |
816 | + ngain = emu->i2c_capture_volume[val][0]; /* Left */ | |
817 | + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | |
818 | + if (force || ngain != ogain) | |
819 | + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff); | |
820 | + ngain = emu->i2c_capture_volume[val][1]; /* Right */ | |
821 | + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ | |
822 | + if (force || ngain != ogain) | |
823 | + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff); | |
824 | + source = 1 << val; | |
825 | + snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ | |
826 | + emu->i2c_capture_source = val; | |
827 | +} | |
828 | + | |
829 | +static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) | |
830 | +{ | |
831 | + u32 tmp; | |
832 | + | |
833 | + if (emu->capture_mic_line_in) { | |
834 | + /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ | |
835 | + tmp = inl(emu->port+GPIO) & ~0x400; | |
836 | + tmp = tmp | 0x400; | |
837 | + outl(tmp, emu->port+GPIO); | |
838 | + /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ | |
839 | + } else { | |
840 | + /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ | |
841 | + tmp = inl(emu->port+GPIO) & ~0x400; | |
842 | + outl(tmp, emu->port+GPIO); | |
843 | + /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ | |
844 | + } | |
845 | +} | |
846 | + | |
847 | +static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) | |
848 | +{ | |
849 | + snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); | |
850 | +} | |
851 | + | |
852 | +/* | |
853 | + */ | |
854 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); | |
855 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); | |
856 | ||
857 | @@ -95,30 +173,12 @@ static int snd_ca0106_shared_spdif_put(s | |
858 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | |
859 | unsigned int val; | |
860 | int change = 0; | |
861 | - u32 mask; | |
862 | ||
863 | val = !!ucontrol->value.integer.value[0]; | |
864 | change = (emu->spdif_enable != val); | |
865 | if (change) { | |
866 | emu->spdif_enable = val; | |
867 | - if (val) { | |
868 | - /* Digital */ | |
869 | - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | |
870 | - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); | |
871 | - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, | |
872 | - snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); | |
873 | - mask = inl(emu->port + GPIO) & ~0x101; | |
874 | - outl(mask, emu->port + GPIO); | |
875 | - | |
876 | - } else { | |
877 | - /* Analog */ | |
878 | - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | |
879 | - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); | |
880 | - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, | |
881 | - snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); | |
882 | - mask = inl(emu->port + GPIO) | 0x101; | |
883 | - outl(mask, emu->port + GPIO); | |
884 | - } | |
885 | + ca0106_spdif_enable(emu); | |
886 | } | |
887 | return change; | |
888 | } | |
889 | @@ -154,8 +214,6 @@ static int snd_ca0106_capture_source_put | |
890 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | |
891 | unsigned int val; | |
892 | int change = 0; | |
893 | - u32 mask; | |
894 | - u32 source; | |
895 | ||
896 | val = ucontrol->value.enumerated.item[0] ; | |
897 | if (val >= 6) | |
898 | @@ -163,9 +221,7 @@ static int snd_ca0106_capture_source_put | |
899 | change = (emu->capture_source != val); | |
900 | if (change) { | |
901 | emu->capture_source = val; | |
902 | - source = (val << 28) | (val << 24) | (val << 20) | (val << 16); | |
903 | - mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; | |
904 | - snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); | |
905 | + ca0106_set_capture_source(emu); | |
906 | } | |
907 | return change; | |
908 | } | |
909 | @@ -200,9 +256,7 @@ static int snd_ca0106_i2c_capture_source | |
910 | { | |
911 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | |
912 | unsigned int source_id; | |
913 | - unsigned int ngain, ogain; | |
914 | int change = 0; | |
915 | - u32 source; | |
916 | /* If the capture source has changed, | |
917 | * update the capture volume from the cached value | |
918 | * for the particular source. | |
919 | @@ -212,18 +266,7 @@ static int snd_ca0106_i2c_capture_source | |
920 | return -EINVAL; | |
921 | change = (emu->i2c_capture_source != source_id); | |
922 | if (change) { | |
923 | - snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | |
924 | - ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ | |
925 | - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | |
926 | - if (ngain != ogain) | |
927 | - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); | |
928 | - ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ | |
929 | - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ | |
930 | - if (ngain != ogain) | |
931 | - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | |
932 | - source = 1 << source_id; | |
933 | - snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ | |
934 | - emu->i2c_capture_source = source_id; | |
935 | + ca0106_set_i2c_capture_source(emu, source_id, 0); | |
936 | } | |
937 | return change; | |
938 | } | |
939 | @@ -271,7 +314,6 @@ static int snd_ca0106_capture_mic_line_i | |
940 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | |
941 | unsigned int val; | |
942 | int change = 0; | |
943 | - u32 tmp; | |
944 | ||
945 | val = ucontrol->value.enumerated.item[0] ; | |
946 | if (val > 1) | |
947 | @@ -279,18 +321,7 @@ static int snd_ca0106_capture_mic_line_i | |
948 | change = (emu->capture_mic_line_in != val); | |
949 | if (change) { | |
950 | emu->capture_mic_line_in = val; | |
951 | - if (val) { | |
952 | - //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | |
953 | - tmp = inl(emu->port+GPIO) & ~0x400; | |
954 | - tmp = tmp | 0x400; | |
955 | - outl(tmp, emu->port+GPIO); | |
956 | - //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); | |
957 | - } else { | |
958 | - //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | |
959 | - tmp = inl(emu->port+GPIO) & ~0x400; | |
960 | - outl(tmp, emu->port+GPIO); | |
961 | - //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); | |
962 | - } | |
963 | + ca0106_set_capture_mic_line_in(emu); | |
964 | } | |
965 | return change; | |
966 | } | |
967 | @@ -359,8 +390,8 @@ static int snd_ca0106_spdif_put(struct s | |
968 | (ucontrol->value.iec958.status[3] << 24); | |
969 | change = val != emu->spdif_bits[idx]; | |
970 | if (change) { | |
971 | - snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); | |
972 | emu->spdif_bits[idx] = val; | |
973 | + ca0106_set_spdif_bits(emu, idx); | |
974 | } | |
975 | return change; | |
976 | } | |
977 | @@ -779,3 +810,50 @@ int __devinit snd_ca0106_mixer(struct sn | |
978 | return 0; | |
979 | } | |
980 | ||
981 | +#ifdef CONFIG_PM | |
982 | +struct ca0106_vol_tbl { | |
983 | + unsigned int channel_id; | |
984 | + unsigned int reg; | |
985 | +}; | |
986 | + | |
987 | +static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { | |
988 | + { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 }, | |
989 | + { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 }, | |
990 | + { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 }, | |
991 | + { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 }, | |
992 | + { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 }, | |
993 | + { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 }, | |
994 | + { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 }, | |
995 | + { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 }, | |
996 | + { 1, CAPTURE_CONTROL }, | |
997 | +}; | |
998 | + | |
999 | +void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip) | |
1000 | +{ | |
1001 | + int i; | |
1002 | + | |
1003 | + /* save volumes */ | |
1004 | + for (i = 0; i < NUM_SAVED_VOLUMES; i++) | |
1005 | + chip->saved_vol[i] = | |
1006 | + snd_ca0106_ptr_read(chip, saved_volumes[i].reg, | |
1007 | + saved_volumes[i].channel_id); | |
1008 | +} | |
1009 | + | |
1010 | +void snd_ca0106_mixer_resume(struct snd_ca0106 *chip) | |
1011 | +{ | |
1012 | + int i; | |
1013 | + | |
1014 | + for (i = 0; i < NUM_SAVED_VOLUMES; i++) | |
1015 | + snd_ca0106_ptr_write(chip, saved_volumes[i].reg, | |
1016 | + saved_volumes[i].channel_id, | |
1017 | + chip->saved_vol[i]); | |
1018 | + | |
1019 | + ca0106_spdif_enable(chip); | |
1020 | + ca0106_set_capture_source(chip); | |
1021 | + ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1); | |
1022 | + for (i = 0; i < 4; i++) | |
1023 | + ca0106_set_spdif_bits(chip, i); | |
1024 | + if (chip->details->i2c_adc) | |
1025 | + ca0106_set_capture_mic_line_in(chip); | |
1026 | +} | |
1027 | +#endif /* CONFIG_PM */ |