diff options
Diffstat (limited to 'sound/isa/ad1848/ad1848_lib.c')
-rw-r--r-- | sound/isa/ad1848/ad1848_lib.c | 487 |
1 files changed, 0 insertions, 487 deletions
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index aa803d38a8ad..e69de29bb2d1 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c | |||
@@ -1,487 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
3 | * Routines for control of AD1848/AD1847/CS4248 | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define SNDRV_MAIN_OBJECT_FILE | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/ad1848.h> | ||
30 | #include <sound/control.h> | ||
31 | #include <sound/tlv.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | |||
34 | #include <asm/io.h> | ||
35 | #include <asm/dma.h> | ||
36 | |||
37 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
38 | MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248"); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | #if 0 | ||
42 | #define SNDRV_DEBUG_MCE | ||
43 | #endif | ||
44 | |||
45 | /* | ||
46 | * Some variables | ||
47 | */ | ||
48 | |||
49 | static unsigned char snd_ad1848_original_image[16] = | ||
50 | { | ||
51 | 0x00, /* 00 - lic */ | ||
52 | 0x00, /* 01 - ric */ | ||
53 | 0x9f, /* 02 - la1ic */ | ||
54 | 0x9f, /* 03 - ra1ic */ | ||
55 | 0x9f, /* 04 - la2ic */ | ||
56 | 0x9f, /* 05 - ra2ic */ | ||
57 | 0xbf, /* 06 - loc */ | ||
58 | 0xbf, /* 07 - roc */ | ||
59 | 0x20, /* 08 - dfr */ | ||
60 | AD1848_AUTOCALIB, /* 09 - ic */ | ||
61 | 0x00, /* 0a - pc */ | ||
62 | 0x00, /* 0b - ti */ | ||
63 | 0x00, /* 0c - mi */ | ||
64 | 0x00, /* 0d - lbc */ | ||
65 | 0x00, /* 0e - dru */ | ||
66 | 0x00, /* 0f - drl */ | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | * Basic I/O functions | ||
71 | */ | ||
72 | |||
73 | static void snd_ad1848_wait(struct snd_wss *chip) | ||
74 | { | ||
75 | int timeout; | ||
76 | |||
77 | for (timeout = 250; timeout > 0; timeout--) { | ||
78 | if ((inb(chip->port + CS4231P(REGSEL)) & AD1848_INIT) == 0) | ||
79 | break; | ||
80 | udelay(100); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void snd_ad1848_out(struct snd_wss *chip, | ||
85 | unsigned char reg, | ||
86 | unsigned char value) | ||
87 | { | ||
88 | snd_ad1848_wait(chip); | ||
89 | #ifdef CONFIG_SND_DEBUG | ||
90 | if (inb(chip->port + CS4231P(REGSEL)) & AD1848_INIT) | ||
91 | snd_printk(KERN_WARNING "auto calibration time out - " | ||
92 | "reg = 0x%x, value = 0x%x\n", reg, value); | ||
93 | #endif | ||
94 | outb(chip->mce_bit | reg, chip->port + CS4231P(REGSEL)); | ||
95 | outb(chip->image[reg] = value, chip->port + CS4231P(REG)); | ||
96 | mb(); | ||
97 | snd_printdd("codec out - reg 0x%x = 0x%x\n", | ||
98 | chip->mce_bit | reg, value); | ||
99 | } | ||
100 | |||
101 | EXPORT_SYMBOL(snd_ad1848_out); | ||
102 | |||
103 | static unsigned char snd_ad1848_in(struct snd_wss *chip, unsigned char reg) | ||
104 | { | ||
105 | snd_ad1848_wait(chip); | ||
106 | #ifdef CONFIG_SND_DEBUG | ||
107 | if (inb(chip->port + CS4231P(REGSEL)) & AD1848_INIT) | ||
108 | snd_printk(KERN_WARNING "auto calibration time out - " | ||
109 | "reg = 0x%x\n", reg); | ||
110 | #endif | ||
111 | outb(chip->mce_bit | reg, chip->port + CS4231P(REGSEL)); | ||
112 | mb(); | ||
113 | return inb(chip->port + CS4231P(REG)); | ||
114 | } | ||
115 | |||
116 | #if 0 | ||
117 | |||
118 | static void snd_ad1848_debug(struct snd_wss *chip) | ||
119 | { | ||
120 | printk(KERN_DEBUG "AD1848 REGS: INDEX = 0x%02x ", inb(chip->port + CS4231P(REGSEL))); | ||
121 | printk(KERN_DEBUG " STATUS = 0x%02x\n", inb(chip->port + CS4231P(STATUS))); | ||
122 | printk(KERN_DEBUG " 0x00: left input = 0x%02x ", snd_ad1848_in(chip, 0x00)); | ||
123 | printk(KERN_DEBUG " 0x08: playback format = 0x%02x\n", snd_ad1848_in(chip, 0x08)); | ||
124 | printk(KERN_DEBUG " 0x01: right input = 0x%02x ", snd_ad1848_in(chip, 0x01)); | ||
125 | printk(KERN_DEBUG " 0x09: iface (CFIG 1) = 0x%02x\n", snd_ad1848_in(chip, 0x09)); | ||
126 | printk(KERN_DEBUG " 0x02: AUXA left = 0x%02x ", snd_ad1848_in(chip, 0x02)); | ||
127 | printk(KERN_DEBUG " 0x0a: pin control = 0x%02x\n", snd_ad1848_in(chip, 0x0a)); | ||
128 | printk(KERN_DEBUG " 0x03: AUXA right = 0x%02x ", snd_ad1848_in(chip, 0x03)); | ||
129 | printk(KERN_DEBUG " 0x0b: init & status = 0x%02x\n", snd_ad1848_in(chip, 0x0b)); | ||
130 | printk(KERN_DEBUG " 0x04: AUXB left = 0x%02x ", snd_ad1848_in(chip, 0x04)); | ||
131 | printk(KERN_DEBUG " 0x0c: revision & mode = 0x%02x\n", snd_ad1848_in(chip, 0x0c)); | ||
132 | printk(KERN_DEBUG " 0x05: AUXB right = 0x%02x ", snd_ad1848_in(chip, 0x05)); | ||
133 | printk(KERN_DEBUG " 0x0d: loopback = 0x%02x\n", snd_ad1848_in(chip, 0x0d)); | ||
134 | printk(KERN_DEBUG " 0x06: left output = 0x%02x ", snd_ad1848_in(chip, 0x06)); | ||
135 | printk(KERN_DEBUG " 0x0e: data upr count = 0x%02x\n", snd_ad1848_in(chip, 0x0e)); | ||
136 | printk(KERN_DEBUG " 0x07: right output = 0x%02x ", snd_ad1848_in(chip, 0x07)); | ||
137 | printk(KERN_DEBUG " 0x0f: data lwr count = 0x%02x\n", snd_ad1848_in(chip, 0x0f)); | ||
138 | } | ||
139 | |||
140 | #endif | ||
141 | |||
142 | /* | ||
143 | * AD1848 detection / MCE routines | ||
144 | */ | ||
145 | |||
146 | static void snd_ad1848_mce_up(struct snd_wss *chip) | ||
147 | { | ||
148 | unsigned long flags; | ||
149 | int timeout; | ||
150 | |||
151 | snd_ad1848_wait(chip); | ||
152 | #ifdef CONFIG_SND_DEBUG | ||
153 | if (inb(chip->port + CS4231P(REGSEL)) & AD1848_INIT) | ||
154 | snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n"); | ||
155 | #endif | ||
156 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
157 | chip->mce_bit |= AD1848_MCE; | ||
158 | timeout = inb(chip->port + CS4231P(REGSEL)); | ||
159 | if (timeout == 0x80) | ||
160 | snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); | ||
161 | if (!(timeout & AD1848_MCE)) | ||
162 | outb(chip->mce_bit | (timeout & 0x1f), | ||
163 | chip->port + CS4231P(REGSEL)); | ||
164 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
165 | } | ||
166 | |||
167 | static void snd_ad1848_mce_down(struct snd_wss *chip) | ||
168 | { | ||
169 | unsigned long flags, timeout; | ||
170 | int reg; | ||
171 | |||
172 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
173 | for (timeout = 5; timeout > 0; timeout--) | ||
174 | inb(chip->port + CS4231P(REGSEL)); | ||
175 | /* end of cleanup sequence */ | ||
176 | for (timeout = 12000; | ||
177 | timeout > 0 && (inb(chip->port + CS4231P(REGSEL)) & AD1848_INIT); | ||
178 | timeout--) | ||
179 | udelay(100); | ||
180 | |||
181 | snd_printdd("(1) timeout = %ld\n", timeout); | ||
182 | |||
183 | #ifdef CONFIG_SND_DEBUG | ||
184 | if (inb(chip->port + CS4231P(REGSEL)) & AD1848_INIT) | ||
185 | snd_printk(KERN_WARNING | ||
186 | "mce_down [0x%lx] - auto calibration time out (0)\n", | ||
187 | chip->port + CS4231P(REGSEL)); | ||
188 | #endif | ||
189 | |||
190 | chip->mce_bit &= ~AD1848_MCE; | ||
191 | reg = inb(chip->port + CS4231P(REGSEL)); | ||
192 | outb(chip->mce_bit | (reg & 0x1f), chip->port + CS4231P(REGSEL)); | ||
193 | if (reg == 0x80) | ||
194 | snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); | ||
195 | if ((reg & AD1848_MCE) == 0) { | ||
196 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low. | ||
202 | * It may take up to 5 sample periods (at most 907 us @ 5.5125 kHz) for | ||
203 | * the process to _start_, so it is important to wait at least that long | ||
204 | * before checking. Otherwise we might think AC has finished when it | ||
205 | * has in fact not begun. It could take 128 (no AC) or 384 (AC) cycles | ||
206 | * for ACI to drop. This gives a wait of at most 70 ms with a more | ||
207 | * typical value of 3-9 ms. | ||
208 | */ | ||
209 | timeout = jiffies + msecs_to_jiffies(250); | ||
210 | do { | ||
211 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
212 | msleep(1); | ||
213 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
214 | reg = snd_ad1848_in(chip, AD1848_TEST_INIT) & | ||
215 | AD1848_CALIB_IN_PROGRESS; | ||
216 | } while (reg && time_before(jiffies, timeout)); | ||
217 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
218 | if (reg) | ||
219 | snd_printk(KERN_ERR | ||
220 | "mce_down - auto calibration time out (2)\n"); | ||
221 | |||
222 | snd_printdd("(4) jiffies = %lu\n", jiffies); | ||
223 | snd_printd("mce_down - exit = 0x%x\n", | ||
224 | inb(chip->port + CS4231P(REGSEL))); | ||
225 | } | ||
226 | |||
227 | static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id) | ||
228 | { | ||
229 | struct snd_wss *chip = dev_id; | ||
230 | |||
231 | if ((chip->mode & WSS_MODE_PLAY) && chip->playback_substream) | ||
232 | snd_pcm_period_elapsed(chip->playback_substream); | ||
233 | if ((chip->mode & WSS_MODE_RECORD) && chip->capture_substream) | ||
234 | snd_pcm_period_elapsed(chip->capture_substream); | ||
235 | outb(0, chip->port + CS4231P(STATUS)); /* clear global interrupt bit */ | ||
236 | return IRQ_HANDLED; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | |||
241 | */ | ||
242 | |||
243 | static void snd_ad1848_thinkpad_twiddle(struct snd_wss *chip, int on) | ||
244 | { | ||
245 | int tmp; | ||
246 | |||
247 | if (!chip->thinkpad_flag) return; | ||
248 | |||
249 | outb(0x1c, AD1848_THINKPAD_CTL_PORT1); | ||
250 | tmp = inb(AD1848_THINKPAD_CTL_PORT2); | ||
251 | |||
252 | if (on) | ||
253 | /* turn it on */ | ||
254 | tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT; | ||
255 | else | ||
256 | /* turn it off */ | ||
257 | tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT; | ||
258 | |||
259 | outb(tmp, AD1848_THINKPAD_CTL_PORT2); | ||
260 | |||
261 | } | ||
262 | |||
263 | #ifdef CONFIG_PM | ||
264 | static void snd_ad1848_suspend(struct snd_wss *chip) | ||
265 | { | ||
266 | snd_pcm_suspend_all(chip->pcm); | ||
267 | if (chip->thinkpad_flag) | ||
268 | snd_ad1848_thinkpad_twiddle(chip, 0); | ||
269 | } | ||
270 | |||
271 | static void snd_ad1848_resume(struct snd_wss *chip) | ||
272 | { | ||
273 | int i; | ||
274 | |||
275 | if (chip->thinkpad_flag) | ||
276 | snd_ad1848_thinkpad_twiddle(chip, 1); | ||
277 | |||
278 | /* clear any pendings IRQ */ | ||
279 | inb(chip->port + CS4231P(STATUS)); | ||
280 | outb(0, chip->port + CS4231P(STATUS)); | ||
281 | mb(); | ||
282 | |||
283 | snd_ad1848_mce_down(chip); | ||
284 | for (i = 0; i < 16; i++) | ||
285 | snd_ad1848_out(chip, i, chip->image[i]); | ||
286 | snd_ad1848_mce_up(chip); | ||
287 | snd_ad1848_mce_down(chip); | ||
288 | } | ||
289 | #endif /* CONFIG_PM */ | ||
290 | |||
291 | static int snd_ad1848_probe(struct snd_wss *chip) | ||
292 | { | ||
293 | unsigned long flags; | ||
294 | int i, id, rev, ad1847; | ||
295 | unsigned char *ptr; | ||
296 | |||
297 | #if 0 | ||
298 | snd_ad1848_debug(chip); | ||
299 | #endif | ||
300 | id = ad1847 = 0; | ||
301 | for (i = 0; i < 1000; i++) { | ||
302 | mb(); | ||
303 | if (inb(chip->port + CS4231P(REGSEL)) & AD1848_INIT) | ||
304 | udelay(500); | ||
305 | else { | ||
306 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
307 | snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); | ||
308 | snd_ad1848_out(chip, AD1848_LEFT_INPUT, 0xaa); | ||
309 | snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45); | ||
310 | rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT); | ||
311 | if (rev == 0x65) { | ||
312 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
313 | id = 1; | ||
314 | ad1847 = 1; | ||
315 | break; | ||
316 | } | ||
317 | if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) { | ||
318 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
319 | id = 1; | ||
320 | break; | ||
321 | } | ||
322 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
323 | } | ||
324 | } | ||
325 | if (id != 1) | ||
326 | return -ENODEV; /* no valid device found */ | ||
327 | if (chip->hardware == WSS_HW_DETECT) { | ||
328 | if (ad1847) { | ||
329 | chip->hardware = WSS_HW_AD1847; | ||
330 | } else { | ||
331 | chip->hardware = WSS_HW_AD1848; | ||
332 | rev = snd_ad1848_in(chip, AD1848_MISC_INFO); | ||
333 | if (rev & 0x80) { | ||
334 | chip->hardware = WSS_HW_CS4248; | ||
335 | } else if ((rev & 0x0f) == 0x0a) { | ||
336 | snd_ad1848_out(chip, AD1848_MISC_INFO, 0x40); | ||
337 | for (i = 0; i < 16; ++i) { | ||
338 | if (snd_ad1848_in(chip, i) != snd_ad1848_in(chip, i + 16)) { | ||
339 | chip->hardware = WSS_HW_CMI8330; | ||
340 | break; | ||
341 | } | ||
342 | } | ||
343 | snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
348 | inb(chip->port + CS4231P(STATUS)); /* clear any pendings IRQ */ | ||
349 | outb(0, chip->port + CS4231P(STATUS)); | ||
350 | mb(); | ||
351 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
352 | |||
353 | chip->image[AD1848_MISC_INFO] = 0x00; | ||
354 | chip->image[AD1848_IFACE_CTRL] = | ||
355 | (chip->image[AD1848_IFACE_CTRL] & ~AD1848_SINGLE_DMA) | AD1848_SINGLE_DMA; | ||
356 | ptr = (unsigned char *) &chip->image; | ||
357 | snd_ad1848_mce_down(chip); | ||
358 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
359 | for (i = 0; i < 16; i++) /* ok.. fill all AD1848 registers */ | ||
360 | snd_ad1848_out(chip, i, *ptr++); | ||
361 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
362 | snd_ad1848_mce_up(chip); | ||
363 | /* init needed for WSS pcm */ | ||
364 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
365 | chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | | ||
366 | AD1848_PLAYBACK_PIO | | ||
367 | AD1848_CAPTURE_ENABLE | | ||
368 | AD1848_CAPTURE_PIO | | ||
369 | AD1848_CALIB_MODE); | ||
370 | chip->image[AD1848_IFACE_CTRL] |= AD1848_AUTOCALIB; | ||
371 | snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]); | ||
372 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
373 | snd_ad1848_mce_down(chip); | ||
374 | return 0; /* all things are ok.. */ | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | |||
379 | */ | ||
380 | |||
381 | static int snd_ad1848_free(struct snd_wss *chip) | ||
382 | { | ||
383 | release_and_free_resource(chip->res_port); | ||
384 | if (chip->irq >= 0) | ||
385 | free_irq(chip->irq, (void *) chip); | ||
386 | if (chip->dma1 >= 0) { | ||
387 | snd_dma_disable(chip->dma1); | ||
388 | free_dma(chip->dma1); | ||
389 | } | ||
390 | kfree(chip); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int snd_ad1848_dev_free(struct snd_device *device) | ||
395 | { | ||
396 | struct snd_wss *chip = device->device_data; | ||
397 | return snd_ad1848_free(chip); | ||
398 | } | ||
399 | |||
400 | int snd_ad1848_create(struct snd_card *card, | ||
401 | unsigned long port, | ||
402 | int irq, int dma, | ||
403 | unsigned short hardware, | ||
404 | struct snd_wss **rchip) | ||
405 | { | ||
406 | static struct snd_device_ops ops = { | ||
407 | .dev_free = snd_ad1848_dev_free, | ||
408 | }; | ||
409 | struct snd_wss *chip; | ||
410 | int err; | ||
411 | |||
412 | *rchip = NULL; | ||
413 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
414 | if (chip == NULL) | ||
415 | return -ENOMEM; | ||
416 | spin_lock_init(&chip->reg_lock); | ||
417 | chip->card = card; | ||
418 | chip->port = port; | ||
419 | chip->irq = -1; | ||
420 | chip->dma1 = -1; | ||
421 | chip->dma2 = -1; | ||
422 | chip->single_dma = 1; | ||
423 | chip->hardware = hardware; | ||
424 | memcpy(&chip->image, &snd_ad1848_original_image, sizeof(snd_ad1848_original_image)); | ||
425 | |||
426 | if ((chip->res_port = request_region(port, 4, "AD1848")) == NULL) { | ||
427 | snd_printk(KERN_ERR "ad1848: can't grab port 0x%lx\n", port); | ||
428 | snd_ad1848_free(chip); | ||
429 | return -EBUSY; | ||
430 | } | ||
431 | if (request_irq(irq, snd_ad1848_interrupt, IRQF_DISABLED, "AD1848", (void *) chip)) { | ||
432 | snd_printk(KERN_ERR "ad1848: can't grab IRQ %d\n", irq); | ||
433 | snd_ad1848_free(chip); | ||
434 | return -EBUSY; | ||
435 | } | ||
436 | chip->irq = irq; | ||
437 | if (request_dma(dma, "AD1848")) { | ||
438 | snd_printk(KERN_ERR "ad1848: can't grab DMA %d\n", dma); | ||
439 | snd_ad1848_free(chip); | ||
440 | return -EBUSY; | ||
441 | } | ||
442 | chip->dma1 = dma; | ||
443 | chip->dma2 = dma; | ||
444 | |||
445 | if (hardware == WSS_HW_THINKPAD) { | ||
446 | chip->thinkpad_flag = 1; | ||
447 | chip->hardware = WSS_HW_DETECT; /* reset */ | ||
448 | snd_ad1848_thinkpad_twiddle(chip, 1); | ||
449 | } | ||
450 | |||
451 | if (snd_ad1848_probe(chip) < 0) { | ||
452 | snd_ad1848_free(chip); | ||
453 | return -ENODEV; | ||
454 | } | ||
455 | |||
456 | /* Register device */ | ||
457 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | ||
458 | snd_ad1848_free(chip); | ||
459 | return err; | ||
460 | } | ||
461 | |||
462 | #ifdef CONFIG_PM | ||
463 | chip->suspend = snd_ad1848_suspend; | ||
464 | chip->resume = snd_ad1848_resume; | ||
465 | #endif | ||
466 | |||
467 | *rchip = chip; | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | EXPORT_SYMBOL(snd_ad1848_create); | ||
472 | |||
473 | /* | ||
474 | * INIT part | ||
475 | */ | ||
476 | |||
477 | static int __init alsa_ad1848_init(void) | ||
478 | { | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static void __exit alsa_ad1848_exit(void) | ||
483 | { | ||
484 | } | ||
485 | |||
486 | module_init(alsa_ad1848_init) | ||
487 | module_exit(alsa_ad1848_exit) | ||