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>
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 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
172 if (reg < 0 || reg > 0x3f)
174 reg += 0x40; /* 0x40 upwards are registers. */
175 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
177 outl(reg, emu->port + A_IOCFG);
179 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
181 outl(value, emu->port + A_IOCFG);
183 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
188 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
190 if (reg < 0 || reg > 0x3f)
192 reg += 0x40; /* 0x40 upwards are registers. */
193 outl(reg, emu->port + A_IOCFG);
195 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
197 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
202 /* Each Destination has one and only one Source,
203 * but one Source can feed any number of Destinations simultaneously.
205 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src)
207 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
208 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
209 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
210 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
215 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
220 spin_lock_irqsave(&emu->emu_lock, flags);
221 enable = inl(emu->port + INTE) | intrenb;
222 outl(enable, emu->port + INTE);
223 spin_unlock_irqrestore(&emu->emu_lock, flags);
226 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
231 spin_lock_irqsave(&emu->emu_lock, flags);
232 enable = inl(emu->port + INTE) & ~intrenb;
233 outl(enable, emu->port + INTE);
234 spin_unlock_irqrestore(&emu->emu_lock, flags);
237 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
242 spin_lock_irqsave(&emu->emu_lock, flags);
243 /* voice interrupt */
244 if (voicenum >= 32) {
245 outl(CLIEH << 16, emu->port + PTR);
246 val = inl(emu->port + DATA);
247 val |= 1 << (voicenum - 32);
249 outl(CLIEL << 16, emu->port + PTR);
250 val = inl(emu->port + DATA);
251 val |= 1 << voicenum;
253 outl(val, emu->port + DATA);
254 spin_unlock_irqrestore(&emu->emu_lock, flags);
257 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
262 spin_lock_irqsave(&emu->emu_lock, flags);
263 /* voice interrupt */
264 if (voicenum >= 32) {
265 outl(CLIEH << 16, emu->port + PTR);
266 val = inl(emu->port + DATA);
267 val &= ~(1 << (voicenum - 32));
269 outl(CLIEL << 16, emu->port + PTR);
270 val = inl(emu->port + DATA);
271 val &= ~(1 << voicenum);
273 outl(val, emu->port + DATA);
274 spin_unlock_irqrestore(&emu->emu_lock, flags);
277 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
281 spin_lock_irqsave(&emu->emu_lock, flags);
282 /* voice interrupt */
283 if (voicenum >= 32) {
284 outl(CLIPH << 16, emu->port + PTR);
285 voicenum = 1 << (voicenum - 32);
287 outl(CLIPL << 16, emu->port + PTR);
288 voicenum = 1 << voicenum;
290 outl(voicenum, emu->port + DATA);
291 spin_unlock_irqrestore(&emu->emu_lock, flags);
294 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
299 spin_lock_irqsave(&emu->emu_lock, flags);
300 /* voice interrupt */
301 if (voicenum >= 32) {
302 outl(HLIEH << 16, emu->port + PTR);
303 val = inl(emu->port + DATA);
304 val |= 1 << (voicenum - 32);
306 outl(HLIEL << 16, emu->port + PTR);
307 val = inl(emu->port + DATA);
308 val |= 1 << voicenum;
310 outl(val, emu->port + DATA);
311 spin_unlock_irqrestore(&emu->emu_lock, flags);
314 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
319 spin_lock_irqsave(&emu->emu_lock, flags);
320 /* voice interrupt */
321 if (voicenum >= 32) {
322 outl(HLIEH << 16, emu->port + PTR);
323 val = inl(emu->port + DATA);
324 val &= ~(1 << (voicenum - 32));
326 outl(HLIEL << 16, emu->port + PTR);
327 val = inl(emu->port + DATA);
328 val &= ~(1 << voicenum);
330 outl(val, emu->port + DATA);
331 spin_unlock_irqrestore(&emu->emu_lock, flags);
334 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
338 spin_lock_irqsave(&emu->emu_lock, flags);
339 /* voice interrupt */
340 if (voicenum >= 32) {
341 outl(HLIPH << 16, emu->port + PTR);
342 voicenum = 1 << (voicenum - 32);
344 outl(HLIPL << 16, emu->port + PTR);
345 voicenum = 1 << voicenum;
347 outl(voicenum, emu->port + DATA);
348 spin_unlock_irqrestore(&emu->emu_lock, flags);
351 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
356 spin_lock_irqsave(&emu->emu_lock, flags);
357 /* voice interrupt */
358 if (voicenum >= 32) {
359 outl(SOLEH << 16, emu->port + PTR);
360 sol = inl(emu->port + DATA);
361 sol |= 1 << (voicenum - 32);
363 outl(SOLEL << 16, emu->port + PTR);
364 sol = inl(emu->port + DATA);
365 sol |= 1 << voicenum;
367 outl(sol, emu->port + DATA);
368 spin_unlock_irqrestore(&emu->emu_lock, flags);
371 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
376 spin_lock_irqsave(&emu->emu_lock, flags);
377 /* voice interrupt */
378 if (voicenum >= 32) {
379 outl(SOLEH << 16, emu->port + PTR);
380 sol = inl(emu->port + DATA);
381 sol &= ~(1 << (voicenum - 32));
383 outl(SOLEL << 16, emu->port + PTR);
384 sol = inl(emu->port + DATA);
385 sol &= ~(1 << voicenum);
387 outl(sol, emu->port + DATA);
388 spin_unlock_irqrestore(&emu->emu_lock, flags);
391 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
393 volatile unsigned count;
394 unsigned int newtime = 0, curtime;
396 curtime = inl(emu->port + WC) >> 6;
399 while (count++ < 16384) {
400 newtime = inl(emu->port + WC) >> 6;
401 if (newtime != curtime)
410 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
412 struct snd_emu10k1 *emu = ac97->private_data;
416 spin_lock_irqsave(&emu->emu_lock, flags);
417 outb(reg, emu->port + AC97ADDRESS);
418 val = inw(emu->port + AC97DATA);
419 spin_unlock_irqrestore(&emu->emu_lock, flags);
423 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
425 struct snd_emu10k1 *emu = ac97->private_data;
428 spin_lock_irqsave(&emu->emu_lock, flags);
429 outb(reg, emu->port + AC97ADDRESS);
430 outw(data, emu->port + AC97DATA);
431 spin_unlock_irqrestore(&emu->emu_lock, flags);
435 * convert rate to pitch
438 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
440 static u32 logMagTable[128] = {
441 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
442 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
443 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
444 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
445 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
446 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
447 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
448 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
449 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
450 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
451 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
452 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
453 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
454 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
455 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
456 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
458 static char logSlopeTable[128] = {
459 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
460 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
461 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
462 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
463 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
464 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
465 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
466 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
467 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
468 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
469 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
470 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
471 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
472 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
473 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
474 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
479 return 0; /* Bail out if no leading "1" */
480 rate *= 11185; /* Scale 48000 to 0x20002380 */
481 for (i = 31; i > 0; i--) {
482 if (rate & 0x80000000) { /* Detect leading "1" */
483 return (((unsigned int) (i - 15) << 20) +
484 logMagTable[0x7f & (rate >> 24)] +
485 (0x7f & (rate >> 17)) *
486 logSlopeTable[0x7f & (rate >> 24)]);
491 return 0; /* Should never reach this point */