ALSA: wss_lib: use wss pcm code instead of ad1848 one
[linux-2.6.git] / sound / isa / ad1848 / ad1848_lib.c
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)