2 * Copyright (c) by Jaroslav Kysela <perex@suse.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 <sound/driver.h>
29 #include <linux/time.h>
30 #include <sound/core.h>
31 #include <sound/emu10k1.h>
32 #include <linux/delay.h>
35 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
38 unsigned int regptr, val;
41 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
42 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
44 if (reg & 0xff000000) {
45 unsigned char size, offset;
47 size = (reg >> 24) & 0x3f;
48 offset = (reg >> 16) & 0x1f;
49 mask = ((1 << size) - 1) << offset;
51 spin_lock_irqsave(&emu->emu_lock, flags);
52 outl(regptr, emu->port + PTR);
53 val = inl(emu->port + DATA);
54 spin_unlock_irqrestore(&emu->emu_lock, flags);
56 return (val & mask) >> offset;
58 spin_lock_irqsave(&emu->emu_lock, flags);
59 outl(regptr, emu->port + PTR);
60 val = inl(emu->port + DATA);
61 spin_unlock_irqrestore(&emu->emu_lock, flags);
66 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
68 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
74 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
75 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
77 if (reg & 0xff000000) {
78 unsigned char size, offset;
80 size = (reg >> 24) & 0x3f;
81 offset = (reg >> 16) & 0x1f;
82 mask = ((1 << size) - 1) << offset;
83 data = (data << offset) & mask;
85 spin_lock_irqsave(&emu->emu_lock, flags);
86 outl(regptr, emu->port + PTR);
87 data |= inl(emu->port + DATA) & ~mask;
88 outl(data, emu->port + DATA);
89 spin_unlock_irqrestore(&emu->emu_lock, flags);
91 spin_lock_irqsave(&emu->emu_lock, flags);
92 outl(regptr, emu->port + PTR);
93 outl(data, emu->port + DATA);
94 spin_unlock_irqrestore(&emu->emu_lock, flags);
98 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
100 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
105 unsigned int regptr, val;
107 regptr = (reg << 16) | chn;
109 spin_lock_irqsave(&emu->emu_lock, flags);
110 outl(regptr, emu->port + 0x20 + PTR);
111 val = inl(emu->port + 0x20 + DATA);
112 spin_unlock_irqrestore(&emu->emu_lock, flags);
116 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
124 regptr = (reg << 16) | chn;
126 spin_lock_irqsave(&emu->emu_lock, flags);
127 outl(regptr, emu->port + 0x20 + PTR);
128 outl(data, emu->port + 0x20 + DATA);
129 spin_unlock_irqrestore(&emu->emu_lock, flags);
132 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
135 unsigned int reset, set;
136 unsigned int reg, tmp;
138 if (emu->card_capabilities->ca0108_chip)
139 reg = 0x3c; /* PTR20, reg 0x3c */
141 /* For other chip types the SPI register
142 * is currently unknown. */
145 if (data > 0xffff) /* Only 16bit values allowed */
148 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
149 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
150 set = reset | 0x10000; /* Set xxx1xxxx */
151 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
152 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
153 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
155 /* Wait for status bit to return to 0 */
156 for (n = 0; n < 100; n++) {
158 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
159 if (!(tmp & 0x10000)) {
164 if (result) /* Timed out */
166 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
167 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
171 /* The ADC does not support i2c read, so only write is implemented */
172 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
180 if ((reg > 0x7f) || (value > 0x1ff)) {
181 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
185 tmp = reg << 25 | value << 16;
186 // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
187 /* Not sure what this I2C channel controls. */
188 /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
190 /* This controls the I2C connected to the WM8775 ADC Codec */
191 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
192 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
194 for (retry = 0; retry < 10; retry++) {
195 /* Send the data to i2c */
196 //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
197 //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
199 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
200 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
202 /* Wait till the transaction ends */
205 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
206 // snd_printk("I2C:status=0x%x\n", status);
208 if ((status & I2C_A_ADC_START) == 0)
211 if (timeout > 1000) {
212 snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
216 //Read back and see if the transaction is successful
217 if ((status & I2C_A_ADC_ABORT) == 0)
222 snd_printk(KERN_ERR "Writing to ADC failed!\n");
229 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
231 if (reg < 0 || reg > 0x3f)
233 reg += 0x40; /* 0x40 upwards are registers. */
234 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
236 outl(reg, emu->port + A_IOCFG);
238 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
240 outl(value, emu->port + A_IOCFG);
242 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
247 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
249 if (reg < 0 || reg > 0x3f)
251 reg += 0x40; /* 0x40 upwards are registers. */
252 outl(reg, emu->port + A_IOCFG);
254 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
256 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
261 /* Each Destination has one and only one Source,
262 * but one Source can feed any number of Destinations simultaneously.
264 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src)
266 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
267 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
268 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
269 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
274 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
279 spin_lock_irqsave(&emu->emu_lock, flags);
280 enable = inl(emu->port + INTE) | intrenb;
281 outl(enable, emu->port + INTE);
282 spin_unlock_irqrestore(&emu->emu_lock, flags);
285 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
290 spin_lock_irqsave(&emu->emu_lock, flags);
291 enable = inl(emu->port + INTE) & ~intrenb;
292 outl(enable, emu->port + INTE);
293 spin_unlock_irqrestore(&emu->emu_lock, flags);
296 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
301 spin_lock_irqsave(&emu->emu_lock, flags);
302 /* voice interrupt */
303 if (voicenum >= 32) {
304 outl(CLIEH << 16, emu->port + PTR);
305 val = inl(emu->port + DATA);
306 val |= 1 << (voicenum - 32);
308 outl(CLIEL << 16, emu->port + PTR);
309 val = inl(emu->port + DATA);
310 val |= 1 << voicenum;
312 outl(val, emu->port + DATA);
313 spin_unlock_irqrestore(&emu->emu_lock, flags);
316 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
321 spin_lock_irqsave(&emu->emu_lock, flags);
322 /* voice interrupt */
323 if (voicenum >= 32) {
324 outl(CLIEH << 16, emu->port + PTR);
325 val = inl(emu->port + DATA);
326 val &= ~(1 << (voicenum - 32));
328 outl(CLIEL << 16, emu->port + PTR);
329 val = inl(emu->port + DATA);
330 val &= ~(1 << voicenum);
332 outl(val, emu->port + DATA);
333 spin_unlock_irqrestore(&emu->emu_lock, flags);
336 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
340 spin_lock_irqsave(&emu->emu_lock, flags);
341 /* voice interrupt */
342 if (voicenum >= 32) {
343 outl(CLIPH << 16, emu->port + PTR);
344 voicenum = 1 << (voicenum - 32);
346 outl(CLIPL << 16, emu->port + PTR);
347 voicenum = 1 << voicenum;
349 outl(voicenum, emu->port + DATA);
350 spin_unlock_irqrestore(&emu->emu_lock, flags);
353 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
358 spin_lock_irqsave(&emu->emu_lock, flags);
359 /* voice interrupt */
360 if (voicenum >= 32) {
361 outl(HLIEH << 16, emu->port + PTR);
362 val = inl(emu->port + DATA);
363 val |= 1 << (voicenum - 32);
365 outl(HLIEL << 16, emu->port + PTR);
366 val = inl(emu->port + DATA);
367 val |= 1 << voicenum;
369 outl(val, emu->port + DATA);
370 spin_unlock_irqrestore(&emu->emu_lock, flags);
373 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
378 spin_lock_irqsave(&emu->emu_lock, flags);
379 /* voice interrupt */
380 if (voicenum >= 32) {
381 outl(HLIEH << 16, emu->port + PTR);
382 val = inl(emu->port + DATA);
383 val &= ~(1 << (voicenum - 32));
385 outl(HLIEL << 16, emu->port + PTR);
386 val = inl(emu->port + DATA);
387 val &= ~(1 << voicenum);
389 outl(val, emu->port + DATA);
390 spin_unlock_irqrestore(&emu->emu_lock, flags);
393 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
397 spin_lock_irqsave(&emu->emu_lock, flags);
398 /* voice interrupt */
399 if (voicenum >= 32) {
400 outl(HLIPH << 16, emu->port + PTR);
401 voicenum = 1 << (voicenum - 32);
403 outl(HLIPL << 16, emu->port + PTR);
404 voicenum = 1 << voicenum;
406 outl(voicenum, emu->port + DATA);
407 spin_unlock_irqrestore(&emu->emu_lock, flags);
410 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
415 spin_lock_irqsave(&emu->emu_lock, flags);
416 /* voice interrupt */
417 if (voicenum >= 32) {
418 outl(SOLEH << 16, emu->port + PTR);
419 sol = inl(emu->port + DATA);
420 sol |= 1 << (voicenum - 32);
422 outl(SOLEL << 16, emu->port + PTR);
423 sol = inl(emu->port + DATA);
424 sol |= 1 << voicenum;
426 outl(sol, emu->port + DATA);
427 spin_unlock_irqrestore(&emu->emu_lock, flags);
430 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
435 spin_lock_irqsave(&emu->emu_lock, flags);
436 /* voice interrupt */
437 if (voicenum >= 32) {
438 outl(SOLEH << 16, emu->port + PTR);
439 sol = inl(emu->port + DATA);
440 sol &= ~(1 << (voicenum - 32));
442 outl(SOLEL << 16, emu->port + PTR);
443 sol = inl(emu->port + DATA);
444 sol &= ~(1 << voicenum);
446 outl(sol, emu->port + DATA);
447 spin_unlock_irqrestore(&emu->emu_lock, flags);
450 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
452 volatile unsigned count;
453 unsigned int newtime = 0, curtime;
455 curtime = inl(emu->port + WC) >> 6;
458 while (count++ < 16384) {
459 newtime = inl(emu->port + WC) >> 6;
460 if (newtime != curtime)
469 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
471 struct snd_emu10k1 *emu = ac97->private_data;
475 spin_lock_irqsave(&emu->emu_lock, flags);
476 outb(reg, emu->port + AC97ADDRESS);
477 val = inw(emu->port + AC97DATA);
478 spin_unlock_irqrestore(&emu->emu_lock, flags);
482 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
484 struct snd_emu10k1 *emu = ac97->private_data;
487 spin_lock_irqsave(&emu->emu_lock, flags);
488 outb(reg, emu->port + AC97ADDRESS);
489 outw(data, emu->port + AC97DATA);
490 spin_unlock_irqrestore(&emu->emu_lock, flags);
494 * convert rate to pitch
497 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
499 static u32 logMagTable[128] = {
500 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
501 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
502 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
503 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
504 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
505 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
506 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
507 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
508 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
509 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
510 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
511 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
512 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
513 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
514 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
515 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
517 static char logSlopeTable[128] = {
518 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
519 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
520 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
521 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
522 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
523 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
524 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
525 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
526 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
527 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
528 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
529 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
530 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
531 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
532 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
533 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
538 return 0; /* Bail out if no leading "1" */
539 rate *= 11185; /* Scale 48000 to 0x20002380 */
540 for (i = 31; i > 0; i--) {
541 if (rate & 0x80000000) { /* Detect leading "1" */
542 return (((unsigned int) (i - 15) << 20) +
543 logMagTable[0x7f & (rate >> 24)] +
544 (0x7f & (rate >> 17)) *
545 logSlopeTable[0x7f & (rate >> 24)]);
550 return 0; /* Should never reach this point */