blob: 3e7a2a33a5cad3a2dbf8f05f8add115a868634aa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips
4 *
5 * Bugs:
6 * - sometimes record brokes playback with WSS portion of
7 * Yamaha OPL3-SA3 chip
8 * - CS4231 (GUS MAX) - still trouble with occasional noises
9 * - broken initialization?
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#include <sound/driver.h>
28#include <linux/delay.h>
29#include <linux/pm.h>
30#include <linux/init.h>
31#include <linux/interrupt.h>
32#include <linux/slab.h>
33#include <linux/ioport.h>
34#include <sound/core.h>
35#include <sound/cs4231.h>
36#include <sound/pcm_params.h>
37
38#include <asm/io.h>
39#include <asm/dma.h>
40#include <asm/irq.h>
41
42MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
43MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
44MODULE_LICENSE("GPL");
45
46#if 0
47#define SNDRV_DEBUG_MCE
48#endif
49
50/*
51 * Some variables
52 */
53
54static unsigned char freq_bits[14] = {
55 /* 5510 */ 0x00 | CS4231_XTAL2,
56 /* 6620 */ 0x0E | CS4231_XTAL2,
57 /* 8000 */ 0x00 | CS4231_XTAL1,
58 /* 9600 */ 0x0E | CS4231_XTAL1,
59 /* 11025 */ 0x02 | CS4231_XTAL2,
60 /* 16000 */ 0x02 | CS4231_XTAL1,
61 /* 18900 */ 0x04 | CS4231_XTAL2,
62 /* 22050 */ 0x06 | CS4231_XTAL2,
63 /* 27042 */ 0x04 | CS4231_XTAL1,
64 /* 32000 */ 0x06 | CS4231_XTAL1,
65 /* 33075 */ 0x0C | CS4231_XTAL2,
66 /* 37800 */ 0x08 | CS4231_XTAL2,
67 /* 44100 */ 0x0A | CS4231_XTAL2,
68 /* 48000 */ 0x0C | CS4231_XTAL1
69};
70
71static unsigned int rates[14] = {
72 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
73 27042, 32000, 33075, 37800, 44100, 48000
74};
75
76static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
77 .count = 14,
78 .list = rates,
79 .mask = 0,
80};
81
82static int snd_cs4231_xrate(snd_pcm_runtime_t *runtime)
83{
84 return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
85}
86
87static unsigned char snd_cs4231_original_image[32] =
88{
89 0x00, /* 00/00 - lic */
90 0x00, /* 01/01 - ric */
91 0x9f, /* 02/02 - la1ic */
92 0x9f, /* 03/03 - ra1ic */
93 0x9f, /* 04/04 - la2ic */
94 0x9f, /* 05/05 - ra2ic */
95 0xbf, /* 06/06 - loc */
96 0xbf, /* 07/07 - roc */
97 0x20, /* 08/08 - pdfr */
98 CS4231_AUTOCALIB, /* 09/09 - ic */
99 0x00, /* 0a/10 - pc */
100 0x00, /* 0b/11 - ti */
101 CS4231_MODE2, /* 0c/12 - mi */
102 0xfc, /* 0d/13 - lbc */
103 0x00, /* 0e/14 - pbru */
104 0x00, /* 0f/15 - pbrl */
105 0x80, /* 10/16 - afei */
106 0x01, /* 11/17 - afeii */
107 0x9f, /* 12/18 - llic */
108 0x9f, /* 13/19 - rlic */
109 0x00, /* 14/20 - tlb */
110 0x00, /* 15/21 - thb */
111 0x00, /* 16/22 - la3mic/reserved */
112 0x00, /* 17/23 - ra3mic/reserved */
113 0x00, /* 18/24 - afs */
114 0x00, /* 19/25 - lamoc/version */
115 0xcf, /* 1a/26 - mioc */
116 0x00, /* 1b/27 - ramoc/reserved */
117 0x20, /* 1c/28 - cdfr */
118 0x00, /* 1d/29 - res4 */
119 0x00, /* 1e/30 - cbru */
120 0x00, /* 1f/31 - cbrl */
121};
122
123/*
124 * Basic I/O functions
125 */
126
127#if !defined(EBUS_SUPPORT) && !defined(SBUS_SUPPORT)
128#define __CS4231_INLINE__ inline
129#else
130#define __CS4231_INLINE__ /* nothing */
131#endif
132
133static __CS4231_INLINE__ void cs4231_outb(cs4231_t *chip, u8 offset, u8 val)
134{
135#ifdef EBUS_SUPPORT
136 if (chip->ebus->flag) {
137 writeb(val, chip->port + (offset << 2));
138 } else {
139#endif
140#ifdef SBUS_SUPPORT
141 sbus_writeb(val, chip->port + (offset << 2));
142#endif
143#ifdef EBUS_SUPPORT
144 }
145#endif
146#ifdef LEGACY_SUPPORT
147 outb(val, chip->port + offset);
148#endif
149}
150
151static __CS4231_INLINE__ u8 cs4231_inb(cs4231_t *chip, u8 offset)
152{
153#ifdef EBUS_SUPPORT
154 if (chip->ebus_flag) {
155 return readb(chip->port + (offset << 2));
156 } else {
157#endif
158#ifdef SBUS_SUPPORT
159 return sbus_readb(chip->port + (offset << 2));
160#endif
161#ifdef EBUS_SUPPORT
162 }
163#endif
164#ifdef LEGACY_SUPPORT
165 return inb(chip->port + offset);
166#endif
167}
168
169static void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,
170 unsigned char mask, unsigned char value)
171{
172 int timeout;
173 unsigned char tmp;
174
175 for (timeout = 250;
176 timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
177 timeout--)
178 udelay(100);
179#ifdef CONFIG_SND_DEBUG
180 if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
181 snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
182#endif
183 if (chip->calibrate_mute) {
184 chip->image[reg] &= mask;
185 chip->image[reg] |= value;
186 } else {
187 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
188 mb();
189 tmp = (chip->image[reg] & mask) | value;
190 cs4231_outb(chip, CS4231P(REG), tmp);
191 chip->image[reg] = tmp;
192 mb();
193 }
194}
195
196static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char value)
197{
198 int timeout;
199
200 for (timeout = 250;
201 timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
202 timeout--)
203 udelay(10);
204 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
205 cs4231_outb(chip, CS4231P(REG), value);
206 mb();
207}
208
209void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char value)
210{
211 int timeout;
212
213 for (timeout = 250;
214 timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
215 timeout--)
216 udelay(100);
217#ifdef CONFIG_SND_DEBUG
218 if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
219 snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
220#endif
221 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
222 cs4231_outb(chip, CS4231P(REG), value);
223 chip->image[reg] = value;
224 mb();
225#if 0
226 printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);
227#endif
228}
229
230unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
231{
232 int timeout;
233
234 for (timeout = 250;
235 timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
236 timeout--)
237 udelay(100);
238#ifdef CONFIG_SND_DEBUG
239 if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
240 snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
241#endif
242 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
243 mb();
244 return cs4231_inb(chip, CS4231P(REG));
245}
246
247void snd_cs4236_ext_out(cs4231_t *chip, unsigned char reg, unsigned char val)
248{
249 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
250 cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
251 cs4231_outb(chip, CS4231P(REG), val);
252 chip->eimage[CS4236_REG(reg)] = val;
253#if 0
254 printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
255#endif
256}
257
258unsigned char snd_cs4236_ext_in(cs4231_t *chip, unsigned char reg)
259{
260 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
261 cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
262#if 1
263 return cs4231_inb(chip, CS4231P(REG));
264#else
265 {
266 unsigned char res;
267 res = cs4231_inb(chip, CS4231P(REG));
268 printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
269 return res;
270 }
271#endif
272}
273
274#if 0
275
276static void snd_cs4231_debug(cs4231_t *chip)
277{
278 printk("CS4231 REGS: INDEX = 0x%02x ", cs4231_inb(chip, CS4231P(REGSEL)));
279 printk(" STATUS = 0x%02x\n", cs4231_inb(chip, CS4231P(STATUS)));
280 printk(" 0x00: left input = 0x%02x ", snd_cs4231_in(chip, 0x00));
281 printk(" 0x10: alt 1 (CFIG 2) = 0x%02x\n", snd_cs4231_in(chip, 0x10));
282 printk(" 0x01: right input = 0x%02x ", snd_cs4231_in(chip, 0x01));
283 printk(" 0x11: alt 2 (CFIG 3) = 0x%02x\n", snd_cs4231_in(chip, 0x11));
284 printk(" 0x02: GF1 left input = 0x%02x ", snd_cs4231_in(chip, 0x02));
285 printk(" 0x12: left line in = 0x%02x\n", snd_cs4231_in(chip, 0x12));
286 printk(" 0x03: GF1 right input = 0x%02x ", snd_cs4231_in(chip, 0x03));
287 printk(" 0x13: right line in = 0x%02x\n", snd_cs4231_in(chip, 0x13));
288 printk(" 0x04: CD left input = 0x%02x ", snd_cs4231_in(chip, 0x04));
289 printk(" 0x14: timer low = 0x%02x\n", snd_cs4231_in(chip, 0x14));
290 printk(" 0x05: CD right input = 0x%02x ", snd_cs4231_in(chip, 0x05));
291 printk(" 0x15: timer high = 0x%02x\n", snd_cs4231_in(chip, 0x15));
292 printk(" 0x06: left output = 0x%02x ", snd_cs4231_in(chip, 0x06));
293 printk(" 0x16: left MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x16));
294 printk(" 0x07: right output = 0x%02x ", snd_cs4231_in(chip, 0x07));
295 printk(" 0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));
296 printk(" 0x08: playback format = 0x%02x ", snd_cs4231_in(chip, 0x08));
297 printk(" 0x18: IRQ status = 0x%02x\n", snd_cs4231_in(chip, 0x18));
298 printk(" 0x09: iface (CFIG 1) = 0x%02x ", snd_cs4231_in(chip, 0x09));
299 printk(" 0x19: left line out = 0x%02x\n", snd_cs4231_in(chip, 0x19));
300 printk(" 0x0a: pin control = 0x%02x ", snd_cs4231_in(chip, 0x0a));
301 printk(" 0x1a: mono control = 0x%02x\n", snd_cs4231_in(chip, 0x1a));
302 printk(" 0x0b: init & status = 0x%02x ", snd_cs4231_in(chip, 0x0b));
303 printk(" 0x1b: right line out = 0x%02x\n", snd_cs4231_in(chip, 0x1b));
304 printk(" 0x0c: revision & mode = 0x%02x ", snd_cs4231_in(chip, 0x0c));
305 printk(" 0x1c: record format = 0x%02x\n", snd_cs4231_in(chip, 0x1c));
306 printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d));
307 printk(" 0x1d: var freq (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x1d));
308 printk(" 0x0e: ply upr count = 0x%02x ", snd_cs4231_in(chip, 0x0e));
309 printk(" 0x1e: ply lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
310 printk(" 0x0f: rec upr count = 0x%02x ", snd_cs4231_in(chip, 0x0f));
311 printk(" 0x1f: rec lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1f));
312}
313
314#endif
315
316/*
317 * CS4231 detection / MCE routines
318 */
319
320static void snd_cs4231_busy_wait(cs4231_t *chip)
321{
322 int timeout;
323
324 /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
325 for (timeout = 5; timeout > 0; timeout--)
326 cs4231_inb(chip, CS4231P(REGSEL));
327 /* end of cleanup sequence */
328 for (timeout = 250;
329 timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
330 timeout--)
331 udelay(10);
332}
333
334void snd_cs4231_mce_up(cs4231_t *chip)
335{
336 unsigned long flags;
337 int timeout;
338
339 for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--)
340 udelay(100);
341#ifdef CONFIG_SND_DEBUG
342 if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
343 snd_printk("mce_up - auto calibration time out (0)\n");
344#endif
345 spin_lock_irqsave(&chip->reg_lock, flags);
346 chip->mce_bit |= CS4231_MCE;
347 timeout = cs4231_inb(chip, CS4231P(REGSEL));
348 if (timeout == 0x80)
349 snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
350 if (!(timeout & CS4231_MCE))
351 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
352 spin_unlock_irqrestore(&chip->reg_lock, flags);
353}
354
355void snd_cs4231_mce_down(cs4231_t *chip)
356{
357 unsigned long flags;
358 int timeout;
359
360 snd_cs4231_busy_wait(chip);
361#if 0
362 printk("(1) timeout = %i\n", timeout);
363#endif
364#ifdef CONFIG_SND_DEBUG
365 if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
366 snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
367#endif
368 spin_lock_irqsave(&chip->reg_lock, flags);
369 chip->mce_bit &= ~CS4231_MCE;
370 timeout = cs4231_inb(chip, CS4231P(REGSEL));
371 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
372 spin_unlock_irqrestore(&chip->reg_lock, flags);
373 if (timeout == 0x80)
374 snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
375 if ((timeout & CS4231_MCE) == 0 ||
376 !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
377 return;
378 }
379 snd_cs4231_busy_wait(chip);
380
381 /* calibration process */
382
383 for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--)
384 udelay(10);
385 if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) {
386 snd_printd("cs4231_mce_down - auto calibration time out (1)\n");
387 return;
388 }
389#if 0
390 printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);
391#endif
392 /* in 10 ms increments, check condition, up to 250 ms */
393 timeout = 25;
394 while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) {
395 if (--timeout < 0) {
396 snd_printk("mce_down - auto calibration time out (2)\n");
397 return;
398 }
399 msleep(10);
400 }
401#if 0
402 printk("(3) jiffies = %li\n", jiffies);
403#endif
404 /* in 10 ms increments, check condition, up to 100 ms */
405 timeout = 10;
406 while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
407 if (--timeout < 0) {
408 snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
409 return;
410 }
411 msleep(10);
412 }
413#if 0
414 printk("(4) jiffies = %li\n", jiffies);
415 snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL)));
416#endif
417}
418
419static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
420{
421 switch (format & 0xe0) {
422 case CS4231_LINEAR_16:
423 case CS4231_LINEAR_16_BIG:
424 size >>= 1;
425 break;
426 case CS4231_ADPCM_16:
427 return size >> 2;
428 }
429 if (format & CS4231_STEREO)
430 size >>= 1;
431 return size;
432}
433
434static int snd_cs4231_trigger(snd_pcm_substream_t *substream,
435 int cmd)
436{
437 cs4231_t *chip = snd_pcm_substream_chip(substream);
438 int result = 0;
439 unsigned int what;
440 struct list_head *pos;
441 snd_pcm_substream_t *s;
442 int do_start;
443
444#if 0
445 printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS)));
446#endif
447
448 switch (cmd) {
449 case SNDRV_PCM_TRIGGER_START:
450 case SNDRV_PCM_TRIGGER_RESUME:
451 do_start = 1; break;
452 case SNDRV_PCM_TRIGGER_STOP:
453 case SNDRV_PCM_TRIGGER_SUSPEND:
454 do_start = 0; break;
455 default:
456 return -EINVAL;
457 }
458
459 what = 0;
460 snd_pcm_group_for_each(pos, substream) {
461 s = snd_pcm_group_substream_entry(pos);
462 if (s == chip->playback_substream) {
463 what |= CS4231_PLAYBACK_ENABLE;
464 snd_pcm_trigger_done(s, substream);
465 } else if (s == chip->capture_substream) {
466 what |= CS4231_RECORD_ENABLE;
467 snd_pcm_trigger_done(s, substream);
468 }
469 }
470 spin_lock(&chip->reg_lock);
471 if (do_start) {
472 chip->image[CS4231_IFACE_CTRL] |= what;
473 if (chip->trigger)
474 chip->trigger(chip, what, 1);
475 } else {
476 chip->image[CS4231_IFACE_CTRL] &= ~what;
477 if (chip->trigger)
478 chip->trigger(chip, what, 0);
479 }
480 snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
481 spin_unlock(&chip->reg_lock);
482#if 0
483 snd_cs4231_debug(chip);
484#endif
485 return result;
486}
487
488/*
489 * CODEC I/O
490 */
491
492static unsigned char snd_cs4231_get_rate(unsigned int rate)
493{
494 int i;
495
496 for (i = 0; i < 14; i++)
497 if (rate == rates[i])
498 return freq_bits[i];
499 // snd_BUG();
500 return freq_bits[13];
501}
502
503static unsigned char snd_cs4231_get_format(cs4231_t *chip,
504 int format,
505 int channels)
506{
507 unsigned char rformat;
508
509 rformat = CS4231_LINEAR_8;
510 switch (format) {
511 case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break;
512 case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break;
513 case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break;
514 case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break;
515 case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break;
516 }
517 if (channels > 1)
518 rformat |= CS4231_STEREO;
519#if 0
520 snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
521#endif
522 return rformat;
523}
524
525static void snd_cs4231_calibrate_mute(cs4231_t *chip, int mute)
526{
527 unsigned long flags;
528
529 mute = mute ? 1 : 0;
530 spin_lock_irqsave(&chip->reg_lock, flags);
531 if (chip->calibrate_mute == mute) {
532 spin_unlock_irqrestore(&chip->reg_lock, flags);
533 return;
534 }
535 if (!mute) {
536 snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]);
537 snd_cs4231_dout(chip, CS4231_RIGHT_INPUT, chip->image[CS4231_RIGHT_INPUT]);
538 snd_cs4231_dout(chip, CS4231_LOOPBACK, chip->image[CS4231_LOOPBACK]);
539 }
540 snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
541 snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
542 snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
543 snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
544 snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
545 snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
546 snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN, mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
547 snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN, mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
548 snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
549 if (chip->hardware == CS4231_HW_INTERWAVE) {
550 snd_cs4231_dout(chip, CS4231_LEFT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]);
551 snd_cs4231_dout(chip, CS4231_RIGHT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_MIC_INPUT]);
552 snd_cs4231_dout(chip, CS4231_LINE_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_LEFT_OUTPUT]);
553 snd_cs4231_dout(chip, CS4231_LINE_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_RIGHT_OUTPUT]);
554 }
555 chip->calibrate_mute = mute;
556 spin_unlock_irqrestore(&chip->reg_lock, flags);
557}
558
559static void snd_cs4231_playback_format(cs4231_t *chip,
560 snd_pcm_hw_params_t *params,
561 unsigned char pdfr)
562{
563 unsigned long flags;
564 int full_calib = 1;
565
566 down(&chip->mce_mutex);
567 snd_cs4231_calibrate_mute(chip, 1);
568 if (chip->hardware == CS4231_HW_CS4231A ||
569 (chip->hardware & CS4231_HW_CS4232_MASK)) {
570 spin_lock_irqsave(&chip->reg_lock, flags);
571 if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) { /* rate is same? */
572 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
573 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
574 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);
575 udelay(100); /* Fixes audible clicks at least on GUS MAX */
576 full_calib = 0;
577 }
578 spin_unlock_irqrestore(&chip->reg_lock, flags);
579 }
580 if (full_calib) {
581 snd_cs4231_mce_up(chip);
582 spin_lock_irqsave(&chip->reg_lock, flags);
583 if (chip->hardware != CS4231_HW_INTERWAVE && !chip->single_dma) {
584 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
585 (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?
586 (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :
587 pdfr);
588 } else {
589 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
590 }
591 spin_unlock_irqrestore(&chip->reg_lock, flags);
592 snd_cs4231_mce_down(chip);
593 }
594 snd_cs4231_calibrate_mute(chip, 0);
595 up(&chip->mce_mutex);
596}
597
598static void snd_cs4231_capture_format(cs4231_t *chip,
599 snd_pcm_hw_params_t *params,
600 unsigned char cdfr)
601{
602 unsigned long flags;
603 int full_calib = 1;
604
605 down(&chip->mce_mutex);
606 snd_cs4231_calibrate_mute(chip, 1);
607 if (chip->hardware == CS4231_HW_CS4231A ||
608 (chip->hardware & CS4231_HW_CS4232_MASK)) {
609 spin_lock_irqsave(&chip->reg_lock, flags);
610 if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) || /* rate is same? */
611 (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
612 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
613 snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT] = cdfr);
614 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
615 full_calib = 0;
616 }
617 spin_unlock_irqrestore(&chip->reg_lock, flags);
618 }
619 if (full_calib) {
620 snd_cs4231_mce_up(chip);
621 spin_lock_irqsave(&chip->reg_lock, flags);
622 if (chip->hardware != CS4231_HW_INTERWAVE) {
623 if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
624 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
625 ((chip->single_dma ? cdfr : chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |
626 (cdfr & 0x0f));
627 spin_unlock_irqrestore(&chip->reg_lock, flags);
628 snd_cs4231_mce_down(chip);
629 snd_cs4231_mce_up(chip);
630 spin_lock_irqsave(&chip->reg_lock, flags);
631 }
632 }
633 snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);
634 spin_unlock_irqrestore(&chip->reg_lock, flags);
635 snd_cs4231_mce_down(chip);
636 }
637 snd_cs4231_calibrate_mute(chip, 0);
638 up(&chip->mce_mutex);
639}
640
641/*
642 * Timer interface
643 */
644
645static unsigned long snd_cs4231_timer_resolution(snd_timer_t * timer)
646{
647 cs4231_t *chip = snd_timer_chip(timer);
648 if (chip->hardware & CS4231_HW_CS4236B_MASK)
649 return 14467;
650 else
651 return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
652}
653
654static int snd_cs4231_timer_start(snd_timer_t * timer)
655{
656 unsigned long flags;
657 unsigned int ticks;
658 cs4231_t *chip = snd_timer_chip(timer);
659 spin_lock_irqsave(&chip->reg_lock, flags);
660 ticks = timer->sticks;
661 if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
662 (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
663 (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
664 snd_cs4231_out(chip, CS4231_TIMER_HIGH, chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8));
665 snd_cs4231_out(chip, CS4231_TIMER_LOW, chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks);
666 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE);
667 }
668 spin_unlock_irqrestore(&chip->reg_lock, flags);
669 return 0;
670}
671
672static int snd_cs4231_timer_stop(snd_timer_t * timer)
673{
674 unsigned long flags;
675 cs4231_t *chip = snd_timer_chip(timer);
676 spin_lock_irqsave(&chip->reg_lock, flags);
677 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);
678 spin_unlock_irqrestore(&chip->reg_lock, flags);
679 return 0;
680}
681
682static void snd_cs4231_init(cs4231_t *chip)
683{
684 unsigned long flags;
685
686 snd_cs4231_mce_down(chip);
687
688#ifdef SNDRV_DEBUG_MCE
689 snd_printk("init: (1)\n");
690#endif
691 snd_cs4231_mce_up(chip);
692 spin_lock_irqsave(&chip->reg_lock, flags);
693 chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
694 CS4231_RECORD_ENABLE | CS4231_RECORD_PIO |
695 CS4231_CALIB_MODE);
696 chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
697 snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
698 spin_unlock_irqrestore(&chip->reg_lock, flags);
699 snd_cs4231_mce_down(chip);
700
701#ifdef SNDRV_DEBUG_MCE
702 snd_printk("init: (2)\n");
703#endif
704
705 snd_cs4231_mce_up(chip);
706 spin_lock_irqsave(&chip->reg_lock, flags);
707 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
708 spin_unlock_irqrestore(&chip->reg_lock, flags);
709 snd_cs4231_mce_down(chip);
710
711#ifdef SNDRV_DEBUG_MCE
712 snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
713#endif
714
715 spin_lock_irqsave(&chip->reg_lock, flags);
716 snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);
717 spin_unlock_irqrestore(&chip->reg_lock, flags);
718
719 snd_cs4231_mce_up(chip);
720 spin_lock_irqsave(&chip->reg_lock, flags);
721 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);
722 spin_unlock_irqrestore(&chip->reg_lock, flags);
723 snd_cs4231_mce_down(chip);
724
725#ifdef SNDRV_DEBUG_MCE
726 snd_printk("init: (4)\n");
727#endif
728
729 snd_cs4231_mce_up(chip);
730 spin_lock_irqsave(&chip->reg_lock, flags);
731 snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
732 spin_unlock_irqrestore(&chip->reg_lock, flags);
733 snd_cs4231_mce_down(chip);
734
735#ifdef SNDRV_DEBUG_MCE
736 snd_printk("init: (5)\n");
737#endif
738}
739
740static int snd_cs4231_open(cs4231_t *chip, unsigned int mode)
741{
742 unsigned long flags;
743
744 down(&chip->open_mutex);
745 if ((chip->mode & mode) ||
746 ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) {
747 up(&chip->open_mutex);
748 return -EAGAIN;
749 }
750 if (chip->mode & CS4231_MODE_OPEN) {
751 chip->mode |= mode;
752 up(&chip->open_mutex);
753 return 0;
754 }
755 /* ok. now enable and ack CODEC IRQ */
756 spin_lock_irqsave(&chip->reg_lock, flags);
757 snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
758 CS4231_RECORD_IRQ |
759 CS4231_TIMER_IRQ);
760 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
761 cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
762 cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
763 chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
764 snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
765 snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
766 CS4231_RECORD_IRQ |
767 CS4231_TIMER_IRQ);
768 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
769 spin_unlock_irqrestore(&chip->reg_lock, flags);
770
771 chip->mode = mode;
772 up(&chip->open_mutex);
773 return 0;
774}
775
776static void snd_cs4231_close(cs4231_t *chip, unsigned int mode)
777{
778 unsigned long flags;
779
780 down(&chip->open_mutex);
781 chip->mode &= ~mode;
782 if (chip->mode & CS4231_MODE_OPEN) {
783 up(&chip->open_mutex);
784 return;
785 }
786 snd_cs4231_calibrate_mute(chip, 1);
787
788 /* disable IRQ */
789 spin_lock_irqsave(&chip->reg_lock, flags);
790 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
791 cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
792 cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
793 chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
794 snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
795
796 /* now disable record & playback */
797
798 if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
799 CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
800 spin_unlock_irqrestore(&chip->reg_lock, flags);
801 snd_cs4231_mce_up(chip);
802 spin_lock_irqsave(&chip->reg_lock, flags);
803 chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
804 CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
805 snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
806 spin_unlock_irqrestore(&chip->reg_lock, flags);
807 snd_cs4231_mce_down(chip);
808 spin_lock_irqsave(&chip->reg_lock, flags);
809 }
810
811 /* clear IRQ again */
812 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
813 cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
814 cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
815 spin_unlock_irqrestore(&chip->reg_lock, flags);
816
817 snd_cs4231_calibrate_mute(chip, 0);
818
819 chip->mode = 0;
820 up(&chip->open_mutex);
821}
822
823/*
824 * timer open/close
825 */
826
827static int snd_cs4231_timer_open(snd_timer_t * timer)
828{
829 cs4231_t *chip = snd_timer_chip(timer);
830 snd_cs4231_open(chip, CS4231_MODE_TIMER);
831 return 0;
832}
833
834static int snd_cs4231_timer_close(snd_timer_t * timer)
835{
836 cs4231_t *chip = snd_timer_chip(timer);
837 snd_cs4231_close(chip, CS4231_MODE_TIMER);
838 return 0;
839}
840
841static struct _snd_timer_hardware snd_cs4231_timer_table =
842{
843 .flags = SNDRV_TIMER_HW_AUTO,
844 .resolution = 9945,
845 .ticks = 65535,
846 .open = snd_cs4231_timer_open,
847 .close = snd_cs4231_timer_close,
848 .c_resolution = snd_cs4231_timer_resolution,
849 .start = snd_cs4231_timer_start,
850 .stop = snd_cs4231_timer_stop,
851};
852
853/*
854 * ok.. exported functions..
855 */
856
857static int snd_cs4231_playback_hw_params(snd_pcm_substream_t * substream,
858 snd_pcm_hw_params_t * hw_params)
859{
860 cs4231_t *chip = snd_pcm_substream_chip(substream);
861 unsigned char new_pdfr;
862 int err;
863
864 if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
865 return err;
866 new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
867 snd_cs4231_get_rate(params_rate(hw_params));
868 chip->set_playback_format(chip, hw_params, new_pdfr);
869 return 0;
870}
871
872static int snd_cs4231_playback_hw_free(snd_pcm_substream_t * substream)
873{
874 return snd_pcm_lib_free_pages(substream);
875}
876
877#ifdef LEGACY_SUPPORT
878static int snd_cs4231_playback_prepare(snd_pcm_substream_t * substream)
879{
880 cs4231_t *chip = snd_pcm_substream_chip(substream);
881 snd_pcm_runtime_t *runtime = substream->runtime;
882 unsigned long flags;
883 unsigned int size = snd_pcm_lib_buffer_bytes(substream);
884 unsigned int count = snd_pcm_lib_period_bytes(substream);
885
886 spin_lock_irqsave(&chip->reg_lock, flags);
887 chip->p_dma_size = size;
888 chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
889 snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
890 count = snd_cs4231_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
891 snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
892 snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
893 spin_unlock_irqrestore(&chip->reg_lock, flags);
894#if 0
895 snd_cs4231_debug(chip);
896#endif
897 return 0;
898}
899#endif /* LEGACY_SUPPORT */
900
901static int snd_cs4231_capture_hw_params(snd_pcm_substream_t * substream,
902 snd_pcm_hw_params_t * hw_params)
903{
904 cs4231_t *chip = snd_pcm_substream_chip(substream);
905 unsigned char new_cdfr;
906 int err;
907
908 if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
909 return err;
910 new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
911 snd_cs4231_get_rate(params_rate(hw_params));
912 chip->set_capture_format(chip, hw_params, new_cdfr);
913 return 0;
914}
915
916static int snd_cs4231_capture_hw_free(snd_pcm_substream_t * substream)
917{
918 return snd_pcm_lib_free_pages(substream);
919}
920
921#ifdef LEGACY_SUPPORT
922static int snd_cs4231_capture_prepare(snd_pcm_substream_t * substream)
923{
924 cs4231_t *chip = snd_pcm_substream_chip(substream);
925 snd_pcm_runtime_t *runtime = substream->runtime;
926 unsigned long flags;
927 unsigned int size = snd_pcm_lib_buffer_bytes(substream);
928 unsigned int count = snd_pcm_lib_period_bytes(substream);
929
930 spin_lock_irqsave(&chip->reg_lock, flags);
931 chip->c_dma_size = size;
932 chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
933 snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
934 count = snd_cs4231_get_count(chip->image[CS4231_REC_FORMAT], count) - 1;
935 if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
936 snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
937 snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
938 } else {
939 snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
940 snd_cs4231_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8));
941 }
942 spin_unlock_irqrestore(&chip->reg_lock, flags);
943 return 0;
944}
945#endif
946
947static void snd_cs4231_overrange(cs4231_t *chip)
948{
949 unsigned long flags;
950 unsigned char res;
951
952 spin_lock_irqsave(&chip->reg_lock, flags);
953 res = snd_cs4231_in(chip, CS4231_TEST_INIT);
954 spin_unlock_irqrestore(&chip->reg_lock, flags);
955 if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */
956 chip->capture_substream->runtime->overrange++;
957}
958
959irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs)
960{
961 cs4231_t *chip = dev_id;
962 unsigned char status;
963
964 status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
965 if (status & CS4231_TIMER_IRQ) {
966 if (chip->timer)
967 snd_timer_interrupt(chip->timer, chip->timer->sticks);
968 }
969 if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
970 if (status & CS4231_PLAYBACK_IRQ) {
971 if (chip->mode & CS4231_MODE_PLAY) {
972 if (chip->playback_substream)
973 snd_pcm_period_elapsed(chip->playback_substream);
974 }
975 if (chip->mode & CS4231_MODE_RECORD) {
976 if (chip->capture_substream) {
977 snd_cs4231_overrange(chip);
978 snd_pcm_period_elapsed(chip->capture_substream);
979 }
980 }
981 }
982 } else {
983 if (status & CS4231_PLAYBACK_IRQ) {
984 if (chip->playback_substream)
985 snd_pcm_period_elapsed(chip->playback_substream);
986 }
987 if (status & CS4231_RECORD_IRQ) {
988 if (chip->capture_substream) {
989 snd_cs4231_overrange(chip);
990 snd_pcm_period_elapsed(chip->capture_substream);
991 }
992 }
993 }
994
995 spin_lock(&chip->reg_lock);
996 snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
997 spin_unlock(&chip->reg_lock);
998 return IRQ_HANDLED;
999}
1000
1001#ifdef LEGACY_SUPPORT
1002static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t * substream)
1003{
1004 cs4231_t *chip = snd_pcm_substream_chip(substream);
1005 size_t ptr;
1006
1007 if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
1008 return 0;
1009 ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
1010 return bytes_to_frames(substream->runtime, ptr);
1011}
1012
1013static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
1014{
1015 cs4231_t *chip = snd_pcm_substream_chip(substream);
1016 size_t ptr;
1017
1018 if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
1019 return 0;
1020 ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
1021 return bytes_to_frames(substream->runtime, ptr);
1022}
1023#endif /* LEGACY_SUPPORT */
1024
1025/*
1026
1027 */
1028
1029static int snd_cs4231_probe(cs4231_t *chip)
1030{
1031 unsigned long flags;
1032 int i, id, rev;
1033 unsigned char *ptr;
1034 unsigned int hw;
1035
1036#if 0
1037 snd_cs4231_debug(chip);
1038#endif
1039 id = 0;
1040 for (i = 0; i < 50; i++) {
1041 mb();
1042 if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
1043 udelay(2000);
1044 else {
1045 spin_lock_irqsave(&chip->reg_lock, flags);
1046 snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
1047 id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
1048 spin_unlock_irqrestore(&chip->reg_lock, flags);
1049 if (id == 0x0a)
1050 break; /* this is valid value */
1051 }
1052 }
1053 snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id);
1054 if (id != 0x0a)
1055 return -ENODEV; /* no valid device found */
1056
1057 if (((hw = chip->hardware) & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
1058 rev = snd_cs4231_in(chip, CS4231_VERSION) & 0xe7;
1059 snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
1060 if (rev == 0x80) {
1061 unsigned char tmp = snd_cs4231_in(chip, 23);
1062 snd_cs4231_out(chip, 23, ~tmp);
1063 if (snd_cs4231_in(chip, 23) != tmp)
1064 chip->hardware = CS4231_HW_AD1845;
1065 else
1066 chip->hardware = CS4231_HW_CS4231;
1067 } else if (rev == 0xa0) {
1068 chip->hardware = CS4231_HW_CS4231A;
1069 } else if (rev == 0xa2) {
1070 chip->hardware = CS4231_HW_CS4232;
1071 } else if (rev == 0xb2) {
1072 chip->hardware = CS4231_HW_CS4232A;
1073 } else if (rev == 0x83) {
1074 chip->hardware = CS4231_HW_CS4236;
1075 } else if (rev == 0x03) {
1076 chip->hardware = CS4231_HW_CS4236B;
1077 } else {
1078 snd_printk("unknown CS chip with version 0x%x\n", rev);
1079 return -ENODEV; /* unknown CS4231 chip? */
1080 }
1081 }
1082 spin_lock_irqsave(&chip->reg_lock, flags);
1083 cs4231_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */
1084 cs4231_outb(chip, CS4231P(STATUS), 0);
1085 mb();
1086 spin_unlock_irqrestore(&chip->reg_lock, flags);
1087
1088 chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
1089 switch (chip->hardware) {
1090 case CS4231_HW_INTERWAVE:
1091 chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
1092 break;
1093 case CS4231_HW_CS4235:
1094 case CS4231_HW_CS4236B:
1095 case CS4231_HW_CS4237B:
1096 case CS4231_HW_CS4238B:
1097 case CS4231_HW_CS4239:
1098 if (hw == CS4231_HW_DETECT3)
1099 chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;
1100 else
1101 chip->hardware = CS4231_HW_CS4236;
1102 break;
1103 }
1104
1105 chip->image[CS4231_IFACE_CTRL] =
1106 (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
1107 (chip->single_dma ? CS4231_SINGLE_DMA : 0);
1108 chip->image[CS4231_ALT_FEATURE_1] = 0x80;
1109 chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01;
1110 ptr = (unsigned char *) &chip->image;
1111 snd_cs4231_mce_down(chip);
1112 spin_lock_irqsave(&chip->reg_lock, flags);
1113 for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */
1114 snd_cs4231_out(chip, i, *ptr++);
1115 spin_unlock_irqrestore(&chip->reg_lock, flags);
1116 snd_cs4231_mce_up(chip);
1117 snd_cs4231_mce_down(chip);
1118
1119 mdelay(2);
1120
1121 /* ok.. try check hardware version for CS4236+ chips */
1122 if ((hw & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
1123 if (chip->hardware == CS4231_HW_CS4236B) {
1124 rev = snd_cs4236_ext_in(chip, CS4236_VERSION);
1125 snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
1126 id = snd_cs4236_ext_in(chip, CS4236_VERSION);
1127 snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
1128 snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
1129 if ((id & 0x1f) == 0x1d) { /* CS4235 */
1130 chip->hardware = CS4231_HW_CS4235;
1131 switch (id >> 5) {
1132 case 4:
1133 case 5:
1134 case 6:
1135 break;
1136 default:
1137 snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
1138 }
1139 } else if ((id & 0x1f) == 0x0b) { /* CS4236/B */
1140 switch (id >> 5) {
1141 case 4:
1142 case 5:
1143 case 6:
1144 case 7:
1145 chip->hardware = CS4231_HW_CS4236B;
1146 break;
1147 default:
1148 snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
1149 }
1150 } else if ((id & 0x1f) == 0x08) { /* CS4237B */
1151 chip->hardware = CS4231_HW_CS4237B;
1152 switch (id >> 5) {
1153 case 4:
1154 case 5:
1155 case 6:
1156 case 7:
1157 break;
1158 default:
1159 snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
1160 }
1161 } else if ((id & 0x1f) == 0x09) { /* CS4238B */
1162 chip->hardware = CS4231_HW_CS4238B;
1163 switch (id >> 5) {
1164 case 5:
1165 case 6:
1166 case 7:
1167 break;
1168 default:
1169 snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
1170 }
1171 } else if ((id & 0x1f) == 0x1e) { /* CS4239 */
1172 chip->hardware = CS4231_HW_CS4239;
1173 switch (id >> 5) {
1174 case 4:
1175 case 5:
1176 case 6:
1177 break;
1178 default:
1179 snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
1180 }
1181 } else {
1182 snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
1183 }
1184 }
1185 }
1186 return 0; /* all things are ok.. */
1187}
1188
1189/*
1190
1191 */
1192
1193static snd_pcm_hardware_t snd_cs4231_playback =
1194{
1195 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
1196 SNDRV_PCM_INFO_MMAP_VALID |
1197 SNDRV_PCM_INFO_RESUME |
1198 SNDRV_PCM_INFO_SYNC_START),
1199 .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
1200 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
1201 .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
1202 .rate_min = 5510,
1203 .rate_max = 48000,
1204 .channels_min = 1,
1205 .channels_max = 2,
1206 .buffer_bytes_max = (128*1024),
1207 .period_bytes_min = 64,
1208 .period_bytes_max = (128*1024),
1209 .periods_min = 1,
1210 .periods_max = 1024,
1211 .fifo_size = 0,
1212};
1213
1214static snd_pcm_hardware_t snd_cs4231_capture =
1215{
1216 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
1217 SNDRV_PCM_INFO_MMAP_VALID |
1218 SNDRV_PCM_INFO_RESUME |
1219 SNDRV_PCM_INFO_SYNC_START),
1220 .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
1221 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
1222 .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
1223 .rate_min = 5510,
1224 .rate_max = 48000,
1225 .channels_min = 1,
1226 .channels_max = 2,
1227 .buffer_bytes_max = (128*1024),
1228 .period_bytes_min = 64,
1229 .period_bytes_max = (128*1024),
1230 .periods_min = 1,
1231 .periods_max = 1024,
1232 .fifo_size = 0,
1233};
1234
1235/*
1236
1237 */
1238
1239static int snd_cs4231_playback_open(snd_pcm_substream_t * substream)
1240{
1241 cs4231_t *chip = snd_pcm_substream_chip(substream);
1242 snd_pcm_runtime_t *runtime = substream->runtime;
1243 int err;
1244
1245 runtime->hw = snd_cs4231_playback;
1246
1247 /* hardware bug in InterWave chipset */
1248 if (chip->hardware == CS4231_HW_INTERWAVE && chip->dma1 > 3)
1249 runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
1250
1251 /* hardware limitation of cheap chips */
1252 if (chip->hardware == CS4231_HW_CS4235 ||
1253 chip->hardware == CS4231_HW_CS4239)
1254 runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
1255
1256#ifdef LEGACY_SUPPORT
1257 snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
1258 snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
1259
1260 if (chip->claim_dma) {
1261 if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
1262 return err;
1263 }
1264#endif
1265
1266 if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {
1267#ifdef LEGACY_SUPPORT
1268 if (chip->release_dma)
1269 chip->release_dma(chip, chip->dma_private_data, chip->dma1);
1270#endif
1271 snd_free_pages(runtime->dma_area, runtime->dma_bytes);
1272 return err;
1273 }
1274 chip->playback_substream = substream;
1275#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT)
1276 chip->p_periods_sent = 0;
1277#endif
1278 snd_pcm_set_sync(substream);
1279 chip->rate_constraint(runtime);
1280 return 0;
1281}
1282
1283static int snd_cs4231_capture_open(snd_pcm_substream_t * substream)
1284{
1285 cs4231_t *chip = snd_pcm_substream_chip(substream);
1286 snd_pcm_runtime_t *runtime = substream->runtime;
1287 int err;
1288
1289 runtime->hw = snd_cs4231_capture;
1290
1291 /* hardware limitation of cheap chips */
1292 if (chip->hardware == CS4231_HW_CS4235 ||
1293 chip->hardware == CS4231_HW_CS4239)
1294 runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
1295
1296#ifdef LEGACY_SUPPORT
1297 snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
1298 snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
1299
1300 if (chip->claim_dma) {
1301 if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
1302 return err;
1303 }
1304#endif
1305
1306 if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {
1307#ifdef LEGACY_SUPPORT
1308 if (chip->release_dma)
1309 chip->release_dma(chip, chip->dma_private_data, chip->dma2);
1310#endif
1311 snd_free_pages(runtime->dma_area, runtime->dma_bytes);
1312 return err;
1313 }
1314 chip->capture_substream = substream;
1315#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT)
1316 chip->c_periods_sent = 0;
1317#endif
1318 snd_pcm_set_sync(substream);
1319 chip->rate_constraint(runtime);
1320 return 0;
1321}
1322
1323static int snd_cs4231_playback_close(snd_pcm_substream_t * substream)
1324{
1325 cs4231_t *chip = snd_pcm_substream_chip(substream);
1326
1327 chip->playback_substream = NULL;
1328 snd_cs4231_close(chip, CS4231_MODE_PLAY);
1329 return 0;
1330}
1331
1332static int snd_cs4231_capture_close(snd_pcm_substream_t * substream)
1333{
1334 cs4231_t *chip = snd_pcm_substream_chip(substream);
1335
1336 chip->capture_substream = NULL;
1337 snd_cs4231_close(chip, CS4231_MODE_RECORD);
1338 return 0;
1339}
1340
1341#ifdef CONFIG_PM
1342
1343/* lowlevel suspend callback for CS4231 */
1344static void snd_cs4231_suspend(cs4231_t *chip)
1345{
1346 int reg;
1347 unsigned long flags;
1348
1349 spin_lock_irqsave(&chip->reg_lock, flags);
1350 for (reg = 0; reg < 32; reg++)
1351 chip->image[reg] = snd_cs4231_in(chip, reg);
1352 spin_unlock_irqrestore(&chip->reg_lock, flags);
1353}
1354
1355/* lowlevel resume callback for CS4231 */
1356static void snd_cs4231_resume(cs4231_t *chip)
1357{
1358 int reg;
1359 unsigned long flags;
1360 int timeout;
1361
1362 snd_cs4231_mce_up(chip);
1363 spin_lock_irqsave(&chip->reg_lock, flags);
1364 for (reg = 0; reg < 32; reg++) {
1365 switch (reg) {
1366 case CS4231_VERSION:
1367 break;
1368 default:
1369 snd_cs4231_out(chip, reg, chip->image[reg]);
1370 break;
1371 }
1372 }
1373 spin_unlock_irqrestore(&chip->reg_lock, flags);
1374#if 0
1375 snd_cs4231_mce_down(chip);
1376#else
1377 /* The following is a workaround to avoid freeze after resume on TP600E.
1378 This is the first half of copy of snd_cs4231_mce_down(), but doesn't
1379 include rescheduling. -- iwai
1380 */
1381 snd_cs4231_busy_wait(chip);
1382 spin_lock_irqsave(&chip->reg_lock, flags);
1383 chip->mce_bit &= ~CS4231_MCE;
1384 timeout = cs4231_inb(chip, CS4231P(REGSEL));
1385 cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
1386 spin_unlock_irqrestore(&chip->reg_lock, flags);
1387 if (timeout == 0x80)
1388 snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
1389 if ((timeout & CS4231_MCE) == 0 ||
1390 !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
1391 return;
1392 }
1393 snd_cs4231_busy_wait(chip);
1394#endif
1395}
1396
1397static int snd_cs4231_pm_suspend(snd_card_t *card, pm_message_t state)
1398{
1399 cs4231_t *chip = card->pm_private_data;
1400 if (chip->suspend)
1401 chip->suspend(chip);
1402 return 0;
1403}
1404
1405static int snd_cs4231_pm_resume(snd_card_t *card)
1406{
1407 cs4231_t *chip = card->pm_private_data;
1408 if (chip->resume)
1409 chip->resume(chip);
1410 return 0;
1411}
1412#endif /* CONFIG_PM */
1413
1414#ifdef LEGACY_SUPPORT
1415
1416static int snd_cs4231_free(cs4231_t *chip)
1417{
1418 if (chip->res_port) {
1419 release_resource(chip->res_port);
1420 kfree_nocheck(chip->res_port);
1421 }
1422 if (chip->res_cport) {
1423 release_resource(chip->res_cport);
1424 kfree_nocheck(chip->res_cport);
1425 }
1426 if (chip->irq >= 0) {
1427 disable_irq(chip->irq);
1428 if (!(chip->hwshare & CS4231_HWSHARE_IRQ))
1429 free_irq(chip->irq, (void *) chip);
1430 }
1431 if (!(chip->hwshare & CS4231_HWSHARE_DMA1) && chip->dma1 >= 0) {
1432 snd_dma_disable(chip->dma1);
1433 free_dma(chip->dma1);
1434 }
1435 if (!(chip->hwshare & CS4231_HWSHARE_DMA2) && chip->dma2 >= 0 && chip->dma2 != chip->dma1) {
1436 snd_dma_disable(chip->dma2);
1437 free_dma(chip->dma2);
1438 }
1439 if (chip->timer)
1440 snd_device_free(chip->card, chip->timer);
1441 kfree(chip);
1442 return 0;
1443}
1444
1445static int snd_cs4231_dev_free(snd_device_t *device)
1446{
1447 cs4231_t *chip = device->device_data;
1448 return snd_cs4231_free(chip);
1449}
1450
1451#endif /* LEGACY_SUPPORT */
1452
1453const char *snd_cs4231_chip_id(cs4231_t *chip)
1454{
1455 switch (chip->hardware) {
1456 case CS4231_HW_CS4231: return "CS4231";
1457 case CS4231_HW_CS4231A: return "CS4231A";
1458 case CS4231_HW_CS4232: return "CS4232";
1459 case CS4231_HW_CS4232A: return "CS4232A";
1460 case CS4231_HW_CS4235: return "CS4235";
1461 case CS4231_HW_CS4236: return "CS4236";
1462 case CS4231_HW_CS4236B: return "CS4236B";
1463 case CS4231_HW_CS4237B: return "CS4237B";
1464 case CS4231_HW_CS4238B: return "CS4238B";
1465 case CS4231_HW_CS4239: return "CS4239";
1466 case CS4231_HW_INTERWAVE: return "AMD InterWave";
1467 case CS4231_HW_OPL3SA2: return chip->card->shortname;
1468 case CS4231_HW_AD1845: return "AD1845";
1469 default: return "???";
1470 }
1471}
1472
1473static int snd_cs4231_new(snd_card_t * card,
1474 unsigned short hardware,
1475 unsigned short hwshare,
1476 cs4231_t ** rchip)
1477{
1478 cs4231_t *chip;
1479
1480 *rchip = NULL;
1481 chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
1482 if (chip == NULL)
1483 return -ENOMEM;
1484 chip->hardware = hardware;
1485 chip->hwshare = hwshare;
1486
1487 spin_lock_init(&chip->reg_lock);
1488 init_MUTEX(&chip->mce_mutex);
1489 init_MUTEX(&chip->open_mutex);
1490 chip->card = card;
1491 chip->rate_constraint = snd_cs4231_xrate;
1492 chip->set_playback_format = snd_cs4231_playback_format;
1493 chip->set_capture_format = snd_cs4231_capture_format;
1494 memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image));
1495
1496 *rchip = chip;
1497 return 0;
1498}
1499
1500#ifdef LEGACY_SUPPORT
1501
1502int snd_cs4231_create(snd_card_t * card,
1503 unsigned long port,
1504 unsigned long cport,
1505 int irq, int dma1, int dma2,
1506 unsigned short hardware,
1507 unsigned short hwshare,
1508 cs4231_t ** rchip)
1509{
1510 static snd_device_ops_t ops = {
1511 .dev_free = snd_cs4231_dev_free,
1512 };
1513 cs4231_t *chip;
1514 int err;
1515
1516 err = snd_cs4231_new(card, hardware, hwshare, &chip);
1517 if (err < 0)
1518 return err;
1519
1520 chip->irq = -1;
1521 chip->dma1 = -1;
1522 chip->dma2 = -1;
1523
1524 if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) {
1525 snd_printk(KERN_ERR "cs4231: can't grab port 0x%lx\n", port);
1526 snd_cs4231_free(chip);
1527 return -EBUSY;
1528 }
1529 chip->port = port;
1530 if ((long)cport >= 0 && (chip->res_cport = request_region(cport, 8, "CS4232 Control")) == NULL) {
1531 snd_printk(KERN_ERR "cs4231: can't grab control port 0x%lx\n", cport);
1532 snd_cs4231_free(chip);
1533 return -ENODEV;
1534 }
1535 chip->cport = cport;
1536 if (!(hwshare & CS4231_HWSHARE_IRQ) && request_irq(irq, snd_cs4231_interrupt, SA_INTERRUPT, "CS4231", (void *) chip)) {
1537 snd_printk(KERN_ERR "cs4231: can't grab IRQ %d\n", irq);
1538 snd_cs4231_free(chip);
1539 return -EBUSY;
1540 }
1541 chip->irq = irq;
1542 if (!(hwshare & CS4231_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) {
1543 snd_printk(KERN_ERR "cs4231: can't grab DMA1 %d\n", dma1);
1544 snd_cs4231_free(chip);
1545 return -EBUSY;
1546 }
1547 chip->dma1 = dma1;
1548 if (!(hwshare & CS4231_HWSHARE_DMA2) && dma1 != dma2 && dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) {
1549 snd_printk(KERN_ERR "cs4231: can't grab DMA2 %d\n", dma2);
1550 snd_cs4231_free(chip);
1551 return -EBUSY;
1552 }
1553 if (dma1 == dma2 || dma2 < 0) {
1554 chip->single_dma = 1;
1555 chip->dma2 = chip->dma1;
1556 } else
1557 chip->dma2 = dma2;
1558
1559 /* global setup */
1560 if (snd_cs4231_probe(chip) < 0) {
1561 snd_cs4231_free(chip);
1562 return -ENODEV;
1563 }
1564 snd_cs4231_init(chip);
1565
1566 if (chip->hardware & CS4231_HW_CS4232_MASK) {
1567 if (chip->res_cport == NULL)
1568 snd_printk("CS4232 control port features are not accessible\n");
1569 }
1570
1571 /* Register device */
1572 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
1573 snd_cs4231_free(chip);
1574 return err;
1575 }
1576
1577#ifdef CONFIG_PM
1578 /* Power Management */
1579 chip->suspend = snd_cs4231_suspend;
1580 chip->resume = snd_cs4231_resume;
1581 snd_card_set_isa_pm_callback(card, snd_cs4231_pm_suspend, snd_cs4231_pm_resume, chip);
1582#endif
1583
1584 *rchip = chip;
1585 return 0;
1586}
1587
1588#endif /* LEGACY_SUPPORT */
1589
1590static snd_pcm_ops_t snd_cs4231_playback_ops = {
1591 .open = snd_cs4231_playback_open,
1592 .close = snd_cs4231_playback_close,
1593 .ioctl = snd_pcm_lib_ioctl,
1594 .hw_params = snd_cs4231_playback_hw_params,
1595 .hw_free = snd_cs4231_playback_hw_free,
1596 .prepare = snd_cs4231_playback_prepare,
1597 .trigger = snd_cs4231_trigger,
1598 .pointer = snd_cs4231_playback_pointer,
1599};
1600
1601static snd_pcm_ops_t snd_cs4231_capture_ops = {
1602 .open = snd_cs4231_capture_open,
1603 .close = snd_cs4231_capture_close,
1604 .ioctl = snd_pcm_lib_ioctl,
1605 .hw_params = snd_cs4231_capture_hw_params,
1606 .hw_free = snd_cs4231_capture_hw_free,
1607 .prepare = snd_cs4231_capture_prepare,
1608 .trigger = snd_cs4231_trigger,
1609 .pointer = snd_cs4231_capture_pointer,
1610};
1611
1612static void snd_cs4231_pcm_free(snd_pcm_t *pcm)
1613{
1614 cs4231_t *chip = pcm->private_data;
1615 chip->pcm = NULL;
1616 snd_pcm_lib_preallocate_free_for_all(pcm);
1617}
1618
1619int snd_cs4231_pcm(cs4231_t *chip, int device, snd_pcm_t **rpcm)
1620{
1621 snd_pcm_t *pcm;
1622 int err;
1623
1624 if ((err = snd_pcm_new(chip->card, "CS4231", device, 1, 1, &pcm)) < 0)
1625 return err;
1626
1627 spin_lock_init(&chip->reg_lock);
1628 init_MUTEX(&chip->mce_mutex);
1629 init_MUTEX(&chip->open_mutex);
1630
1631 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
1632 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
1633
1634 /* global setup */
1635 pcm->private_data = chip;
1636 pcm->private_free = snd_cs4231_pcm_free;
1637 pcm->info_flags = 0;
1638 if (chip->single_dma)
1639 pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
1640 if (chip->hardware != CS4231_HW_INTERWAVE)
1641 pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1642 strcpy(pcm->name, snd_cs4231_chip_id(chip));
1643
1644#ifdef LEGACY_SUPPORT
1645 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1646 snd_dma_isa_data(),
1647 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
1648#else
1649# ifdef EBUS_SUPPORT
1650 if (chip->ebus_flag) {
1651 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1652 chip->dev_u.pdev,
1653 64*1024, 128*1024);
1654 } else {
1655# endif
1656# ifdef SBUS_SUPPORT
1657 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
1658 chip->dev_u.sdev,
1659 64*1024, 128*1024);
1660# endif
1661# ifdef EBUS_SUPPORT
1662 }
1663# endif
1664#endif
1665
1666 chip->pcm = pcm;
1667 if (rpcm)
1668 *rpcm = pcm;
1669 return 0;
1670}
1671
1672static void snd_cs4231_timer_free(snd_timer_t *timer)
1673{
1674 cs4231_t *chip = timer->private_data;
1675 chip->timer = NULL;
1676}
1677
1678int snd_cs4231_timer(cs4231_t *chip, int device, snd_timer_t **rtimer)
1679{
1680 snd_timer_t *timer;
1681 snd_timer_id_t tid;
1682 int err;
1683
1684 /* Timer initialization */
1685 tid.dev_class = SNDRV_TIMER_CLASS_CARD;
1686 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
1687 tid.card = chip->card->number;
1688 tid.device = device;
1689 tid.subdevice = 0;
1690 if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
1691 return err;
1692 strcpy(timer->name, snd_cs4231_chip_id(chip));
1693 timer->private_data = chip;
1694 timer->private_free = snd_cs4231_timer_free;
1695 timer->hw = snd_cs4231_timer_table;
1696 chip->timer = timer;
1697 if (rtimer)
1698 *rtimer = timer;
1699 return 0;
1700}
1701
1702/*
1703 * MIXER part
1704 */
1705
1706static int snd_cs4231_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
1707{
1708 static char *texts[4] = {
1709 "Line", "Aux", "Mic", "Mix"
1710 };
1711 static char *opl3sa_texts[4] = {
1712 "Line", "CD", "Mic", "Mix"
1713 };
1714 static char *gusmax_texts[4] = {
1715 "Line", "Synth", "Mic", "Mix"
1716 };
1717 char **ptexts = texts;
1718 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1719
1720 snd_assert(chip->card != NULL, return -EINVAL);
1721 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1722 uinfo->count = 2;
1723 uinfo->value.enumerated.items = 4;
1724 if (uinfo->value.enumerated.item > 3)
1725 uinfo->value.enumerated.item = 3;
1726 if (!strcmp(chip->card->driver, "GUS MAX"))
1727 ptexts = gusmax_texts;
1728 switch (chip->hardware) {
1729 case CS4231_HW_INTERWAVE: ptexts = gusmax_texts; break;
1730 case CS4231_HW_OPL3SA2: ptexts = opl3sa_texts; break;
1731 }
1732 strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
1733 return 0;
1734}
1735
1736static int snd_cs4231_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1737{
1738 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1739 unsigned long flags;
1740
1741 spin_lock_irqsave(&chip->reg_lock, flags);
1742 ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
1743 ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
1744 spin_unlock_irqrestore(&chip->reg_lock, flags);
1745 return 0;
1746}
1747
1748static int snd_cs4231_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1749{
1750 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1751 unsigned long flags;
1752 unsigned short left, right;
1753 int change;
1754
1755 if (ucontrol->value.enumerated.item[0] > 3 ||
1756 ucontrol->value.enumerated.item[1] > 3)
1757 return -EINVAL;
1758 left = ucontrol->value.enumerated.item[0] << 6;
1759 right = ucontrol->value.enumerated.item[1] << 6;
1760 spin_lock_irqsave(&chip->reg_lock, flags);
1761 left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
1762 right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
1763 change = left != chip->image[CS4231_LEFT_INPUT] ||
1764 right != chip->image[CS4231_RIGHT_INPUT];
1765 snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);
1766 snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);
1767 spin_unlock_irqrestore(&chip->reg_lock, flags);
1768 return change;
1769}
1770
1771int snd_cs4231_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
1772{
1773 int mask = (kcontrol->private_value >> 16) & 0xff;
1774
1775 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1776 uinfo->count = 1;
1777 uinfo->value.integer.min = 0;
1778 uinfo->value.integer.max = mask;
1779 return 0;
1780}
1781
1782int snd_cs4231_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1783{
1784 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1785 unsigned long flags;
1786 int reg = kcontrol->private_value & 0xff;
1787 int shift = (kcontrol->private_value >> 8) & 0xff;
1788 int mask = (kcontrol->private_value >> 16) & 0xff;
1789 int invert = (kcontrol->private_value >> 24) & 0xff;
1790
1791 spin_lock_irqsave(&chip->reg_lock, flags);
1792 ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
1793 spin_unlock_irqrestore(&chip->reg_lock, flags);
1794 if (invert)
1795 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
1796 return 0;
1797}
1798
1799int snd_cs4231_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1800{
1801 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1802 unsigned long flags;
1803 int reg = kcontrol->private_value & 0xff;
1804 int shift = (kcontrol->private_value >> 8) & 0xff;
1805 int mask = (kcontrol->private_value >> 16) & 0xff;
1806 int invert = (kcontrol->private_value >> 24) & 0xff;
1807 int change;
1808 unsigned short val;
1809
1810 val = (ucontrol->value.integer.value[0] & mask);
1811 if (invert)
1812 val = mask - val;
1813 val <<= shift;
1814 spin_lock_irqsave(&chip->reg_lock, flags);
1815 val = (chip->image[reg] & ~(mask << shift)) | val;
1816 change = val != chip->image[reg];
1817 snd_cs4231_out(chip, reg, val);
1818 spin_unlock_irqrestore(&chip->reg_lock, flags);
1819 return change;
1820}
1821
1822int snd_cs4231_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
1823{
1824 int mask = (kcontrol->private_value >> 24) & 0xff;
1825
1826 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1827 uinfo->count = 2;
1828 uinfo->value.integer.min = 0;
1829 uinfo->value.integer.max = mask;
1830 return 0;
1831}
1832
1833int snd_cs4231_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1834{
1835 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1836 unsigned long flags;
1837 int left_reg = kcontrol->private_value & 0xff;
1838 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1839 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1840 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1841 int mask = (kcontrol->private_value >> 24) & 0xff;
1842 int invert = (kcontrol->private_value >> 22) & 1;
1843
1844 spin_lock_irqsave(&chip->reg_lock, flags);
1845 ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
1846 ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
1847 spin_unlock_irqrestore(&chip->reg_lock, flags);
1848 if (invert) {
1849 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
1850 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
1851 }
1852 return 0;
1853}
1854
1855int snd_cs4231_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1856{
1857 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1858 unsigned long flags;
1859 int left_reg = kcontrol->private_value & 0xff;
1860 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1861 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1862 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1863 int mask = (kcontrol->private_value >> 24) & 0xff;
1864 int invert = (kcontrol->private_value >> 22) & 1;
1865 int change;
1866 unsigned short val1, val2;
1867
1868 val1 = ucontrol->value.integer.value[0] & mask;
1869 val2 = ucontrol->value.integer.value[1] & mask;
1870 if (invert) {
1871 val1 = mask - val1;
1872 val2 = mask - val2;
1873 }
1874 val1 <<= shift_left;
1875 val2 <<= shift_right;
1876 spin_lock_irqsave(&chip->reg_lock, flags);
1877 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
1878 val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
1879 change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
1880 snd_cs4231_out(chip, left_reg, val1);
1881 snd_cs4231_out(chip, right_reg, val2);
1882 spin_unlock_irqrestore(&chip->reg_lock, flags);
1883 return change;
1884}
1885
1886static snd_kcontrol_new_t snd_cs4231_controls[] = {
1887CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
1888CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
1889CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
1890CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
1891CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
1892CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
1893CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
1894CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
1895CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),
1896CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
1897CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),
1898CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
1899CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
1900{
1901 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1902 .name = "Capture Source",
1903 .info = snd_cs4231_info_mux,
1904 .get = snd_cs4231_get_mux,
1905 .put = snd_cs4231_put_mux,
1906},
1907CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
1908CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
1909CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1)
1910};
1911
1912int snd_cs4231_mixer(cs4231_t *chip)
1913{
1914 snd_card_t *card;
1915 unsigned int idx;
1916 int err;
1917
1918 snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
1919
1920 card = chip->card;
1921
1922 strcpy(card->mixername, chip->pcm->name);
1923
1924 for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
1925 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip))) < 0)
1926 return err;
1927 }
1928 return 0;
1929}
1930
1931EXPORT_SYMBOL(snd_cs4231_out);
1932EXPORT_SYMBOL(snd_cs4231_in);
1933EXPORT_SYMBOL(snd_cs4236_ext_out);
1934EXPORT_SYMBOL(snd_cs4236_ext_in);
1935EXPORT_SYMBOL(snd_cs4231_mce_up);
1936EXPORT_SYMBOL(snd_cs4231_mce_down);
1937EXPORT_SYMBOL(snd_cs4231_interrupt);
1938EXPORT_SYMBOL(snd_cs4231_chip_id);
1939EXPORT_SYMBOL(snd_cs4231_create);
1940EXPORT_SYMBOL(snd_cs4231_pcm);
1941EXPORT_SYMBOL(snd_cs4231_mixer);
1942EXPORT_SYMBOL(snd_cs4231_timer);
1943EXPORT_SYMBOL(snd_cs4231_info_single);
1944EXPORT_SYMBOL(snd_cs4231_get_single);
1945EXPORT_SYMBOL(snd_cs4231_put_single);
1946EXPORT_SYMBOL(snd_cs4231_info_double);
1947EXPORT_SYMBOL(snd_cs4231_get_double);
1948EXPORT_SYMBOL(snd_cs4231_put_double);
1949
1950/*
1951 * INIT part
1952 */
1953
1954static int __init alsa_cs4231_init(void)
1955{
1956 return 0;
1957}
1958
1959static void __exit alsa_cs4231_exit(void)
1960{
1961}
1962
1963module_init(alsa_cs4231_init)
1964module_exit(alsa_cs4231_exit)