1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
5 * Routines for control of EMU10K1 chips
14 #include <linux/time.h>
15 #include <sound/core.h>
16 #include <sound/emu10k1.h>
17 #include <linux/delay.h>
18 #include <linux/export.h>
21 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
24 unsigned int regptr, val;
27 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
28 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
30 if (reg & 0xff000000) {
31 unsigned char size, offset;
33 size = (reg >> 24) & 0x3f;
34 offset = (reg >> 16) & 0x1f;
35 mask = ((1 << size) - 1) << offset;
37 spin_lock_irqsave(&emu->emu_lock, flags);
38 outl(regptr, emu->port + PTR);
39 val = inl(emu->port + DATA);
40 spin_unlock_irqrestore(&emu->emu_lock, flags);
42 return (val & mask) >> offset;
44 spin_lock_irqsave(&emu->emu_lock, flags);
45 outl(regptr, emu->port + PTR);
46 val = inl(emu->port + DATA);
47 spin_unlock_irqrestore(&emu->emu_lock, flags);
52 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
54 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
62 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
63 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
65 if (reg & 0xff000000) {
66 unsigned char size, offset;
68 size = (reg >> 24) & 0x3f;
69 offset = (reg >> 16) & 0x1f;
70 mask = ((1 << size) - 1) << offset;
71 data = (data << offset) & mask;
73 spin_lock_irqsave(&emu->emu_lock, flags);
74 outl(regptr, emu->port + PTR);
75 data |= inl(emu->port + DATA) & ~mask;
76 outl(data, emu->port + DATA);
77 spin_unlock_irqrestore(&emu->emu_lock, flags);
79 spin_lock_irqsave(&emu->emu_lock, flags);
80 outl(regptr, emu->port + PTR);
81 outl(data, emu->port + DATA);
82 spin_unlock_irqrestore(&emu->emu_lock, flags);
86 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
88 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
93 unsigned int regptr, val;
95 regptr = (reg << 16) | chn;
97 spin_lock_irqsave(&emu->emu_lock, flags);
98 outl(regptr, emu->port + 0x20 + PTR);
99 val = inl(emu->port + 0x20 + DATA);
100 spin_unlock_irqrestore(&emu->emu_lock, flags);
104 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
112 regptr = (reg << 16) | chn;
114 spin_lock_irqsave(&emu->emu_lock, flags);
115 outl(regptr, emu->port + 0x20 + PTR);
116 outl(data, emu->port + 0x20 + DATA);
117 spin_unlock_irqrestore(&emu->emu_lock, flags);
120 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
123 unsigned int reset, set;
124 unsigned int reg, tmp;
128 /* This function is not re-entrant, so protect against it. */
129 spin_lock(&emu->spi_lock);
130 if (emu->card_capabilities->ca0108_chip)
131 reg = 0x3c; /* PTR20, reg 0x3c */
133 /* For other chip types the SPI register
134 * is currently unknown. */
139 /* Only 16bit values allowed */
144 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
145 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
146 set = reset | 0x10000; /* Set xxx1xxxx */
147 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
148 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
149 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
151 /* Wait for status bit to return to 0 */
152 for (n = 0; n < 100; n++) {
154 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
155 if (!(tmp & 0x10000)) {
165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
169 spin_unlock(&emu->spi_lock);
173 /* The ADC does not support i2c read, so only write is implemented */
174 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
184 if ((reg > 0x7f) || (value > 0x1ff)) {
185 dev_err(emu->card->dev, "i2c_write: invalid values.\n");
189 /* This function is not re-entrant, so protect against it. */
190 spin_lock(&emu->i2c_lock);
192 tmp = reg << 25 | value << 16;
194 /* This controls the I2C connected to the WM8775 ADC Codec */
195 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
196 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
198 for (retry = 0; retry < 10; retry++) {
199 /* Send the data to i2c */
201 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
202 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
204 /* Wait till the transaction ends */
207 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
209 if ((status & I2C_A_ADC_START) == 0)
212 if (timeout > 1000) {
213 dev_warn(emu->card->dev,
214 "emu10k1:I2C:timeout status=0x%x\n",
219 //Read back and see if the transaction is successful
220 if ((status & I2C_A_ADC_ABORT) == 0)
225 dev_err(emu->card->dev, "Writing to ADC failed!\n");
226 dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
232 spin_unlock(&emu->i2c_lock);
236 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
242 reg += 0x40; /* 0x40 upwards are registers. */
243 if (value > 0x3f) /* 0 to 0x3f are values */
245 spin_lock_irqsave(&emu->emu_lock, flags);
246 outl(reg, emu->port + A_IOCFG);
248 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
250 outl(value, emu->port + A_IOCFG);
252 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
253 spin_unlock_irqrestore(&emu->emu_lock, flags);
258 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
263 reg += 0x40; /* 0x40 upwards are registers. */
264 spin_lock_irqsave(&emu->emu_lock, flags);
265 outl(reg, emu->port + A_IOCFG);
267 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
269 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
270 spin_unlock_irqrestore(&emu->emu_lock, flags);
275 /* Each Destination has one and only one Source,
276 * but one Source can feed any number of Destinations simultaneously.
278 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
280 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
281 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
282 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
283 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
288 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
293 spin_lock_irqsave(&emu->emu_lock, flags);
294 enable = inl(emu->port + INTE) | intrenb;
295 outl(enable, emu->port + INTE);
296 spin_unlock_irqrestore(&emu->emu_lock, flags);
299 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
304 spin_lock_irqsave(&emu->emu_lock, flags);
305 enable = inl(emu->port + INTE) & ~intrenb;
306 outl(enable, emu->port + INTE);
307 spin_unlock_irqrestore(&emu->emu_lock, flags);
310 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
315 spin_lock_irqsave(&emu->emu_lock, flags);
316 /* voice interrupt */
317 if (voicenum >= 32) {
318 outl(CLIEH << 16, emu->port + PTR);
319 val = inl(emu->port + DATA);
320 val |= 1 << (voicenum - 32);
322 outl(CLIEL << 16, emu->port + PTR);
323 val = inl(emu->port + DATA);
324 val |= 1 << voicenum;
326 outl(val, emu->port + DATA);
327 spin_unlock_irqrestore(&emu->emu_lock, flags);
330 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
335 spin_lock_irqsave(&emu->emu_lock, flags);
336 /* voice interrupt */
337 if (voicenum >= 32) {
338 outl(CLIEH << 16, emu->port + PTR);
339 val = inl(emu->port + DATA);
340 val &= ~(1 << (voicenum - 32));
342 outl(CLIEL << 16, emu->port + PTR);
343 val = inl(emu->port + DATA);
344 val &= ~(1 << voicenum);
346 outl(val, emu->port + DATA);
347 spin_unlock_irqrestore(&emu->emu_lock, flags);
350 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
354 spin_lock_irqsave(&emu->emu_lock, flags);
355 /* voice interrupt */
356 if (voicenum >= 32) {
357 outl(CLIPH << 16, emu->port + PTR);
358 voicenum = 1 << (voicenum - 32);
360 outl(CLIPL << 16, emu->port + PTR);
361 voicenum = 1 << voicenum;
363 outl(voicenum, emu->port + DATA);
364 spin_unlock_irqrestore(&emu->emu_lock, flags);
367 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
372 spin_lock_irqsave(&emu->emu_lock, flags);
373 /* voice interrupt */
374 if (voicenum >= 32) {
375 outl(HLIEH << 16, emu->port + PTR);
376 val = inl(emu->port + DATA);
377 val |= 1 << (voicenum - 32);
379 outl(HLIEL << 16, emu->port + PTR);
380 val = inl(emu->port + DATA);
381 val |= 1 << voicenum;
383 outl(val, emu->port + DATA);
384 spin_unlock_irqrestore(&emu->emu_lock, flags);
387 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
392 spin_lock_irqsave(&emu->emu_lock, flags);
393 /* voice interrupt */
394 if (voicenum >= 32) {
395 outl(HLIEH << 16, emu->port + PTR);
396 val = inl(emu->port + DATA);
397 val &= ~(1 << (voicenum - 32));
399 outl(HLIEL << 16, emu->port + PTR);
400 val = inl(emu->port + DATA);
401 val &= ~(1 << voicenum);
403 outl(val, emu->port + DATA);
404 spin_unlock_irqrestore(&emu->emu_lock, flags);
407 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
411 spin_lock_irqsave(&emu->emu_lock, flags);
412 /* voice interrupt */
413 if (voicenum >= 32) {
414 outl(HLIPH << 16, emu->port + PTR);
415 voicenum = 1 << (voicenum - 32);
417 outl(HLIPL << 16, emu->port + PTR);
418 voicenum = 1 << voicenum;
420 outl(voicenum, emu->port + DATA);
421 spin_unlock_irqrestore(&emu->emu_lock, flags);
424 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
429 spin_lock_irqsave(&emu->emu_lock, flags);
430 /* voice interrupt */
431 if (voicenum >= 32) {
432 outl(SOLEH << 16, emu->port + PTR);
433 sol = inl(emu->port + DATA);
434 sol |= 1 << (voicenum - 32);
436 outl(SOLEL << 16, emu->port + PTR);
437 sol = inl(emu->port + DATA);
438 sol |= 1 << voicenum;
440 outl(sol, emu->port + DATA);
441 spin_unlock_irqrestore(&emu->emu_lock, flags);
444 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
449 spin_lock_irqsave(&emu->emu_lock, flags);
450 /* voice interrupt */
451 if (voicenum >= 32) {
452 outl(SOLEH << 16, emu->port + PTR);
453 sol = inl(emu->port + DATA);
454 sol &= ~(1 << (voicenum - 32));
456 outl(SOLEL << 16, emu->port + PTR);
457 sol = inl(emu->port + DATA);
458 sol &= ~(1 << voicenum);
460 outl(sol, emu->port + DATA);
461 spin_unlock_irqrestore(&emu->emu_lock, flags);
464 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
466 volatile unsigned count;
467 unsigned int newtime = 0, curtime;
469 curtime = inl(emu->port + WC) >> 6;
472 while (count++ < 16384) {
473 newtime = inl(emu->port + WC) >> 6;
474 if (newtime != curtime)
483 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
485 struct snd_emu10k1 *emu = ac97->private_data;
489 spin_lock_irqsave(&emu->emu_lock, flags);
490 outb(reg, emu->port + AC97ADDRESS);
491 val = inw(emu->port + AC97DATA);
492 spin_unlock_irqrestore(&emu->emu_lock, flags);
496 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
498 struct snd_emu10k1 *emu = ac97->private_data;
501 spin_lock_irqsave(&emu->emu_lock, flags);
502 outb(reg, emu->port + AC97ADDRESS);
503 outw(data, emu->port + AC97DATA);
504 spin_unlock_irqrestore(&emu->emu_lock, flags);
508 * convert rate to pitch
511 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
513 static u32 logMagTable[128] = {
514 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
515 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
516 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
517 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
518 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
519 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
520 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
521 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
522 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
523 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
524 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
525 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
526 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
527 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
528 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
529 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
531 static char logSlopeTable[128] = {
532 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
533 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
534 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
535 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
536 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
537 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
538 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
539 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
540 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
541 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
542 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
543 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
544 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
545 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
546 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
547 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
552 return 0; /* Bail out if no leading "1" */
553 rate *= 11185; /* Scale 48000 to 0x20002380 */
554 for (i = 31; i > 0; i--) {
555 if (rate & 0x80000000) { /* Detect leading "1" */
556 return (((unsigned int) (i - 15) << 20) +
557 logMagTable[0x7f & (rate >> 24)] +
558 (0x7f & (rate >> 17)) *
559 logSlopeTable[0x7f & (rate >> 24)]);
564 return 0; /* Should never reach this point */