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)
232 reg += 0x40; /* 0x40 upwards are registers. */
233 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
235 outl(reg, emu->port + A_IOCFG);
237 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
239 outl(value, emu->port + A_IOCFG);
241 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
246 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
250 reg += 0x40; /* 0x40 upwards are registers. */
251 outl(reg, emu->port + A_IOCFG);
253 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
255 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
260 /* Each Destination has one and only one Source,
261 * but one Source can feed any number of Destinations simultaneously.
263 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
265 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
266 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
267 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
268 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
273 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
278 spin_lock_irqsave(&emu->emu_lock, flags);
279 enable = inl(emu->port + INTE) | intrenb;
280 outl(enable, emu->port + INTE);
281 spin_unlock_irqrestore(&emu->emu_lock, flags);
284 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
289 spin_lock_irqsave(&emu->emu_lock, flags);
290 enable = inl(emu->port + INTE) & ~intrenb;
291 outl(enable, emu->port + INTE);
292 spin_unlock_irqrestore(&emu->emu_lock, flags);
295 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
300 spin_lock_irqsave(&emu->emu_lock, flags);
301 /* voice interrupt */
302 if (voicenum >= 32) {
303 outl(CLIEH << 16, emu->port + PTR);
304 val = inl(emu->port + DATA);
305 val |= 1 << (voicenum - 32);
307 outl(CLIEL << 16, emu->port + PTR);
308 val = inl(emu->port + DATA);
309 val |= 1 << voicenum;
311 outl(val, emu->port + DATA);
312 spin_unlock_irqrestore(&emu->emu_lock, flags);
315 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
320 spin_lock_irqsave(&emu->emu_lock, flags);
321 /* voice interrupt */
322 if (voicenum >= 32) {
323 outl(CLIEH << 16, emu->port + PTR);
324 val = inl(emu->port + DATA);
325 val &= ~(1 << (voicenum - 32));
327 outl(CLIEL << 16, emu->port + PTR);
328 val = inl(emu->port + DATA);
329 val &= ~(1 << voicenum);
331 outl(val, emu->port + DATA);
332 spin_unlock_irqrestore(&emu->emu_lock, flags);
335 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
339 spin_lock_irqsave(&emu->emu_lock, flags);
340 /* voice interrupt */
341 if (voicenum >= 32) {
342 outl(CLIPH << 16, emu->port + PTR);
343 voicenum = 1 << (voicenum - 32);
345 outl(CLIPL << 16, emu->port + PTR);
346 voicenum = 1 << voicenum;
348 outl(voicenum, emu->port + DATA);
349 spin_unlock_irqrestore(&emu->emu_lock, flags);
352 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
357 spin_lock_irqsave(&emu->emu_lock, flags);
358 /* voice interrupt */
359 if (voicenum >= 32) {
360 outl(HLIEH << 16, emu->port + PTR);
361 val = inl(emu->port + DATA);
362 val |= 1 << (voicenum - 32);
364 outl(HLIEL << 16, emu->port + PTR);
365 val = inl(emu->port + DATA);
366 val |= 1 << voicenum;
368 outl(val, emu->port + DATA);
369 spin_unlock_irqrestore(&emu->emu_lock, flags);
372 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
377 spin_lock_irqsave(&emu->emu_lock, flags);
378 /* voice interrupt */
379 if (voicenum >= 32) {
380 outl(HLIEH << 16, emu->port + PTR);
381 val = inl(emu->port + DATA);
382 val &= ~(1 << (voicenum - 32));
384 outl(HLIEL << 16, emu->port + PTR);
385 val = inl(emu->port + DATA);
386 val &= ~(1 << voicenum);
388 outl(val, emu->port + DATA);
389 spin_unlock_irqrestore(&emu->emu_lock, flags);
392 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
396 spin_lock_irqsave(&emu->emu_lock, flags);
397 /* voice interrupt */
398 if (voicenum >= 32) {
399 outl(HLIPH << 16, emu->port + PTR);
400 voicenum = 1 << (voicenum - 32);
402 outl(HLIPL << 16, emu->port + PTR);
403 voicenum = 1 << voicenum;
405 outl(voicenum, emu->port + DATA);
406 spin_unlock_irqrestore(&emu->emu_lock, flags);
409 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
414 spin_lock_irqsave(&emu->emu_lock, flags);
415 /* voice interrupt */
416 if (voicenum >= 32) {
417 outl(SOLEH << 16, emu->port + PTR);
418 sol = inl(emu->port + DATA);
419 sol |= 1 << (voicenum - 32);
421 outl(SOLEL << 16, emu->port + PTR);
422 sol = inl(emu->port + DATA);
423 sol |= 1 << voicenum;
425 outl(sol, emu->port + DATA);
426 spin_unlock_irqrestore(&emu->emu_lock, flags);
429 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
434 spin_lock_irqsave(&emu->emu_lock, flags);
435 /* voice interrupt */
436 if (voicenum >= 32) {
437 outl(SOLEH << 16, emu->port + PTR);
438 sol = inl(emu->port + DATA);
439 sol &= ~(1 << (voicenum - 32));
441 outl(SOLEL << 16, emu->port + PTR);
442 sol = inl(emu->port + DATA);
443 sol &= ~(1 << voicenum);
445 outl(sol, emu->port + DATA);
446 spin_unlock_irqrestore(&emu->emu_lock, flags);
449 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
451 volatile unsigned count;
452 unsigned int newtime = 0, curtime;
454 curtime = inl(emu->port + WC) >> 6;
457 while (count++ < 16384) {
458 newtime = inl(emu->port + WC) >> 6;
459 if (newtime != curtime)
468 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
470 struct snd_emu10k1 *emu = ac97->private_data;
474 spin_lock_irqsave(&emu->emu_lock, flags);
475 outb(reg, emu->port + AC97ADDRESS);
476 val = inw(emu->port + AC97DATA);
477 spin_unlock_irqrestore(&emu->emu_lock, flags);
481 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
483 struct snd_emu10k1 *emu = ac97->private_data;
486 spin_lock_irqsave(&emu->emu_lock, flags);
487 outb(reg, emu->port + AC97ADDRESS);
488 outw(data, emu->port + AC97DATA);
489 spin_unlock_irqrestore(&emu->emu_lock, flags);
493 * convert rate to pitch
496 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
498 static u32 logMagTable[128] = {
499 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
500 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
501 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
502 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
503 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
504 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
505 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
506 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
507 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
508 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
509 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
510 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
511 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
512 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
513 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
514 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
516 static char logSlopeTable[128] = {
517 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
518 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
519 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
520 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
521 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
522 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
523 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
524 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
525 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
526 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
527 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
528 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
529 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
530 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
531 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
532 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
537 return 0; /* Bail out if no leading "1" */
538 rate *= 11185; /* Scale 48000 to 0x20002380 */
539 for (i = 31; i > 0; i--) {
540 if (rate & 0x80000000) { /* Detect leading "1" */
541 return (((unsigned int) (i - 15) << 20) +
542 logMagTable[0x7f & (rate >> 24)] +
543 (0x7f & (rate >> 17)) *
544 logSlopeTable[0x7f & (rate >> 24)]);
549 return 0; /* Should never reach this point */