2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 * Routines for control of EMU10K1 chips
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <linux/time.h>
29 #include <sound/core.h>
30 #include <sound/emu10k1.h>
31 #include <linux/delay.h>
34 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
37 unsigned int regptr, val;
40 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
41 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
43 if (reg & 0xff000000) {
44 unsigned char size, offset;
46 size = (reg >> 24) & 0x3f;
47 offset = (reg >> 16) & 0x1f;
48 mask = ((1 << size) - 1) << offset;
50 spin_lock_irqsave(&emu->emu_lock, flags);
51 outl(regptr, emu->port + PTR);
52 val = inl(emu->port + DATA);
53 spin_unlock_irqrestore(&emu->emu_lock, flags);
55 return (val & mask) >> offset;
57 spin_lock_irqsave(&emu->emu_lock, flags);
58 outl(regptr, emu->port + PTR);
59 val = inl(emu->port + DATA);
60 spin_unlock_irqrestore(&emu->emu_lock, flags);
65 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
67 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
73 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
74 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
76 if (reg & 0xff000000) {
77 unsigned char size, offset;
79 size = (reg >> 24) & 0x3f;
80 offset = (reg >> 16) & 0x1f;
81 mask = ((1 << size) - 1) << offset;
82 data = (data << offset) & mask;
84 spin_lock_irqsave(&emu->emu_lock, flags);
85 outl(regptr, emu->port + PTR);
86 data |= inl(emu->port + DATA) & ~mask;
87 outl(data, emu->port + DATA);
88 spin_unlock_irqrestore(&emu->emu_lock, flags);
90 spin_lock_irqsave(&emu->emu_lock, flags);
91 outl(regptr, emu->port + PTR);
92 outl(data, emu->port + DATA);
93 spin_unlock_irqrestore(&emu->emu_lock, flags);
97 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
99 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
104 unsigned int regptr, val;
106 regptr = (reg << 16) | chn;
108 spin_lock_irqsave(&emu->emu_lock, flags);
109 outl(regptr, emu->port + 0x20 + PTR);
110 val = inl(emu->port + 0x20 + DATA);
111 spin_unlock_irqrestore(&emu->emu_lock, flags);
115 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
123 regptr = (reg << 16) | chn;
125 spin_lock_irqsave(&emu->emu_lock, flags);
126 outl(regptr, emu->port + 0x20 + PTR);
127 outl(data, emu->port + 0x20 + DATA);
128 spin_unlock_irqrestore(&emu->emu_lock, flags);
131 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
134 unsigned int reset, set;
135 unsigned int reg, tmp;
137 if (emu->card_capabilities->ca0108_chip)
138 reg = 0x3c; /* PTR20, reg 0x3c */
140 /* For other chip types the SPI register
141 * is currently unknown. */
144 if (data > 0xffff) /* Only 16bit values allowed */
147 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
148 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
149 set = reset | 0x10000; /* Set xxx1xxxx */
150 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
151 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
152 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
154 /* Wait for status bit to return to 0 */
155 for (n = 0; n < 100; n++) {
157 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
158 if (!(tmp & 0x10000)) {
163 if (result) /* Timed out */
165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
170 /* The ADC does not support i2c read, so only write is implemented */
171 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
179 if ((reg > 0x7f) || (value > 0x1ff)) {
180 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
184 tmp = reg << 25 | value << 16;
185 // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
186 /* Not sure what this I2C channel controls. */
187 /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
189 /* This controls the I2C connected to the WM8775 ADC Codec */
190 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
191 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
193 for (retry = 0; retry < 10; retry++) {
194 /* Send the data to i2c */
195 //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
196 //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
198 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
199 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
201 /* Wait till the transaction ends */
204 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
205 // snd_printk("I2C:status=0x%x\n", status);
207 if ((status & I2C_A_ADC_START) == 0)
210 if (timeout > 1000) {
211 snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
215 //Read back and see if the transaction is successful
216 if ((status & I2C_A_ADC_ABORT) == 0)
221 snd_printk(KERN_ERR "Writing to ADC failed!\n");
228 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
234 reg += 0x40; /* 0x40 upwards are registers. */
235 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
237 spin_lock_irqsave(&emu->emu_lock, flags);
238 outl(reg, emu->port + A_IOCFG);
240 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
242 outl(value, emu->port + A_IOCFG);
244 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
245 spin_unlock_irqrestore(&emu->emu_lock, flags);
250 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
255 reg += 0x40; /* 0x40 upwards are registers. */
256 spin_lock_irqsave(&emu->emu_lock, flags);
257 outl(reg, emu->port + A_IOCFG);
259 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
261 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
262 spin_unlock_irqrestore(&emu->emu_lock, flags);
267 /* Each Destination has one and only one Source,
268 * but one Source can feed any number of Destinations simultaneously.
270 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
272 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
273 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
274 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
275 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
280 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
285 spin_lock_irqsave(&emu->emu_lock, flags);
286 enable = inl(emu->port + INTE) | intrenb;
287 outl(enable, emu->port + INTE);
288 spin_unlock_irqrestore(&emu->emu_lock, flags);
291 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
296 spin_lock_irqsave(&emu->emu_lock, flags);
297 enable = inl(emu->port + INTE) & ~intrenb;
298 outl(enable, emu->port + INTE);
299 spin_unlock_irqrestore(&emu->emu_lock, flags);
302 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
307 spin_lock_irqsave(&emu->emu_lock, flags);
308 /* voice interrupt */
309 if (voicenum >= 32) {
310 outl(CLIEH << 16, emu->port + PTR);
311 val = inl(emu->port + DATA);
312 val |= 1 << (voicenum - 32);
314 outl(CLIEL << 16, emu->port + PTR);
315 val = inl(emu->port + DATA);
316 val |= 1 << voicenum;
318 outl(val, emu->port + DATA);
319 spin_unlock_irqrestore(&emu->emu_lock, flags);
322 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
327 spin_lock_irqsave(&emu->emu_lock, flags);
328 /* voice interrupt */
329 if (voicenum >= 32) {
330 outl(CLIEH << 16, emu->port + PTR);
331 val = inl(emu->port + DATA);
332 val &= ~(1 << (voicenum - 32));
334 outl(CLIEL << 16, emu->port + PTR);
335 val = inl(emu->port + DATA);
336 val &= ~(1 << voicenum);
338 outl(val, emu->port + DATA);
339 spin_unlock_irqrestore(&emu->emu_lock, flags);
342 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
346 spin_lock_irqsave(&emu->emu_lock, flags);
347 /* voice interrupt */
348 if (voicenum >= 32) {
349 outl(CLIPH << 16, emu->port + PTR);
350 voicenum = 1 << (voicenum - 32);
352 outl(CLIPL << 16, emu->port + PTR);
353 voicenum = 1 << voicenum;
355 outl(voicenum, emu->port + DATA);
356 spin_unlock_irqrestore(&emu->emu_lock, flags);
359 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
364 spin_lock_irqsave(&emu->emu_lock, flags);
365 /* voice interrupt */
366 if (voicenum >= 32) {
367 outl(HLIEH << 16, emu->port + PTR);
368 val = inl(emu->port + DATA);
369 val |= 1 << (voicenum - 32);
371 outl(HLIEL << 16, emu->port + PTR);
372 val = inl(emu->port + DATA);
373 val |= 1 << voicenum;
375 outl(val, emu->port + DATA);
376 spin_unlock_irqrestore(&emu->emu_lock, flags);
379 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
384 spin_lock_irqsave(&emu->emu_lock, flags);
385 /* voice interrupt */
386 if (voicenum >= 32) {
387 outl(HLIEH << 16, emu->port + PTR);
388 val = inl(emu->port + DATA);
389 val &= ~(1 << (voicenum - 32));
391 outl(HLIEL << 16, emu->port + PTR);
392 val = inl(emu->port + DATA);
393 val &= ~(1 << voicenum);
395 outl(val, emu->port + DATA);
396 spin_unlock_irqrestore(&emu->emu_lock, flags);
399 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
403 spin_lock_irqsave(&emu->emu_lock, flags);
404 /* voice interrupt */
405 if (voicenum >= 32) {
406 outl(HLIPH << 16, emu->port + PTR);
407 voicenum = 1 << (voicenum - 32);
409 outl(HLIPL << 16, emu->port + PTR);
410 voicenum = 1 << voicenum;
412 outl(voicenum, emu->port + DATA);
413 spin_unlock_irqrestore(&emu->emu_lock, flags);
416 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
421 spin_lock_irqsave(&emu->emu_lock, flags);
422 /* voice interrupt */
423 if (voicenum >= 32) {
424 outl(SOLEH << 16, emu->port + PTR);
425 sol = inl(emu->port + DATA);
426 sol |= 1 << (voicenum - 32);
428 outl(SOLEL << 16, emu->port + PTR);
429 sol = inl(emu->port + DATA);
430 sol |= 1 << voicenum;
432 outl(sol, emu->port + DATA);
433 spin_unlock_irqrestore(&emu->emu_lock, flags);
436 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
441 spin_lock_irqsave(&emu->emu_lock, flags);
442 /* voice interrupt */
443 if (voicenum >= 32) {
444 outl(SOLEH << 16, emu->port + PTR);
445 sol = inl(emu->port + DATA);
446 sol &= ~(1 << (voicenum - 32));
448 outl(SOLEL << 16, emu->port + PTR);
449 sol = inl(emu->port + DATA);
450 sol &= ~(1 << voicenum);
452 outl(sol, emu->port + DATA);
453 spin_unlock_irqrestore(&emu->emu_lock, flags);
456 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
458 volatile unsigned count;
459 unsigned int newtime = 0, curtime;
461 curtime = inl(emu->port + WC) >> 6;
464 while (count++ < 16384) {
465 newtime = inl(emu->port + WC) >> 6;
466 if (newtime != curtime)
475 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
477 struct snd_emu10k1 *emu = ac97->private_data;
481 spin_lock_irqsave(&emu->emu_lock, flags);
482 outb(reg, emu->port + AC97ADDRESS);
483 val = inw(emu->port + AC97DATA);
484 spin_unlock_irqrestore(&emu->emu_lock, flags);
488 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
490 struct snd_emu10k1 *emu = ac97->private_data;
493 spin_lock_irqsave(&emu->emu_lock, flags);
494 outb(reg, emu->port + AC97ADDRESS);
495 outw(data, emu->port + AC97DATA);
496 spin_unlock_irqrestore(&emu->emu_lock, flags);
500 * convert rate to pitch
503 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
505 static u32 logMagTable[128] = {
506 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
507 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
508 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
509 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
510 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
511 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
512 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
513 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
514 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
515 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
516 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
517 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
518 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
519 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
520 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
521 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
523 static char logSlopeTable[128] = {
524 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
525 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
526 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
527 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
528 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
529 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
530 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
531 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
532 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
533 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
534 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
535 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
536 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
537 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
538 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
539 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
544 return 0; /* Bail out if no leading "1" */
545 rate *= 11185; /* Scale 48000 to 0x20002380 */
546 for (i = 31; i > 0; i--) {
547 if (rate & 0x80000000) { /* Detect leading "1" */
548 return (((unsigned int) (i - 15) << 20) +
549 logMagTable[0x7f & (rate >> 24)] +
550 (0x7f & (rate >> 17)) *
551 logSlopeTable[0x7f & (rate >> 24)]);
556 return 0; /* Should never reach this point */