aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa/ad1848/ad1848_lib.c
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2008-07-31 15:10:47 -0400
committerJaroslav Kysela <perex@perex.cz>2008-08-06 09:40:02 -0400
commit760fc6b838d8c783c363e8bdb3714bd92a8945c4 (patch)
treebe50fd4d3e3c3d561d62a369066f9ea62d348fbc /sound/isa/ad1848/ad1848_lib.c
parentead893c0deeec165524cc8a06e7e739d7d84b4c4 (diff)
ALSA: wss_lib: use wss detection code instead of ad1848 one
Use the wss detection code and kill the ad1848 library. The library is fully assimilated into the new wss library. This required reworking of the AD1848 family code so the code is changed to correctly detect chips from the AD1848 and CS4231 families. I have tested it on following cards: Gallant SC-6600 (codec: AD1848, driver: snd-sc6600) SoundScape VIVO/90 (codec: AD1845, driver: snd-sscape) SG Waverider (codec: CS4231A, driver: Rene Herman's snd-galaxy) Opti930 (codec: built-in - CS4231 compatible, driver: snd-opti93x) Opti931 (codec: built-in - CS4231 compatible, driver: snd-opti93x) Gallant SC-70P (chip/codec: CS4237B, driver: snd-cs4236) Audio Plus 3D (chip/codec: CMI8330A, driver: snd-cmi8330) Dell Latitude CP (chip/codec: cs4236, driver snd-cs4232) Sound playback and recording works on all these cards. Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Reviewed-by: Rene Herman <rene.herman@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/isa/ad1848/ad1848_lib.c')
-rw-r--r--sound/isa/ad1848/ad1848_lib.c487
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
37MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
38MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248");
39MODULE_LICENSE("GPL");
40
41#if 0
42#define SNDRV_DEBUG_MCE
43#endif
44
45/*
46 * Some variables
47 */
48
49static 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
73static 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
84void 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
101EXPORT_SYMBOL(snd_ad1848_out);
102
103static 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
118static 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
146static 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
167static 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
227static 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
243static 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
264static 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
271static 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
291static 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
381static 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
394static 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
400int 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
471EXPORT_SYMBOL(snd_ad1848_create);
472
473/*
474 * INIT part
475 */
476
477static int __init alsa_ad1848_init(void)
478{
479 return 0;
480}
481
482static void __exit alsa_ad1848_exit(void)
483{
484}
485
486module_init(alsa_ad1848_init)
487module_exit(alsa_ad1848_exit)