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>
32
#include <linux/export.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)
75
snd_printk(KERN_ERR "ptr_write: emu is null!\n");
79
mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
80
regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
82
if (reg & 0xff000000) {
83
unsigned char size, offset;
85
size = (reg >> 24) & 0x3f;
86
offset = (reg >> 16) & 0x1f;
87
mask = ((1 << size) - 1) << offset;
88
data = (data << offset) & mask;
90
spin_lock_irqsave(&emu->emu_lock, flags);
91
outl(regptr, emu->port + PTR);
92
data |= inl(emu->port + DATA) & ~mask;
93
outl(data, emu->port + DATA);
94
spin_unlock_irqrestore(&emu->emu_lock, flags);
96
spin_lock_irqsave(&emu->emu_lock, flags);
97
outl(regptr, emu->port + PTR);
98
outl(data, emu->port + DATA);
99
spin_unlock_irqrestore(&emu->emu_lock, flags);
103
EXPORT_SYMBOL(snd_emu10k1_ptr_write);
105
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
110
unsigned int regptr, val;
112
regptr = (reg << 16) | chn;
114
spin_lock_irqsave(&emu->emu_lock, flags);
115
outl(regptr, emu->port + 0x20 + PTR);
116
val = inl(emu->port + 0x20 + DATA);
117
spin_unlock_irqrestore(&emu->emu_lock, flags);
121
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
129
regptr = (reg << 16) | chn;
131
spin_lock_irqsave(&emu->emu_lock, flags);
132
outl(regptr, emu->port + 0x20 + PTR);
133
outl(data, emu->port + 0x20 + DATA);
134
spin_unlock_irqrestore(&emu->emu_lock, flags);
137
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
140
unsigned int reset, set;
141
unsigned int reg, tmp;
145
/* This function is not re-entrant, so protect against it. */
146
spin_lock(&emu->spi_lock);
147
if (emu->card_capabilities->ca0108_chip)
148
reg = 0x3c; /* PTR20, reg 0x3c */
150
/* For other chip types the SPI register
151
* is currently unknown. */
156
/* Only 16bit values allowed */
161
tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
162
reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
163
set = reset | 0x10000; /* Set xxx1xxxx */
164
snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
165
tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
166
snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
168
/* Wait for status bit to return to 0 */
169
for (n = 0; n < 100; n++) {
171
tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
172
if (!(tmp & 0x10000)) {
182
snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
183
tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
186
spin_unlock(&emu->spi_lock);
190
/* The ADC does not support i2c read, so only write is implemented */
191
int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
201
if ((reg > 0x7f) || (value > 0x1ff)) {
202
snd_printk(KERN_ERR "i2c_write: invalid values.\n");
206
/* This function is not re-entrant, so protect against it. */
207
spin_lock(&emu->i2c_lock);
209
tmp = reg << 25 | value << 16;
211
/* This controls the I2C connected to the WM8775 ADC Codec */
212
snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
213
tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
215
for (retry = 0; retry < 10; retry++) {
216
/* Send the data to i2c */
218
tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
219
snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
221
/* Wait till the transaction ends */
224
status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
226
if ((status & I2C_A_ADC_START) == 0)
229
if (timeout > 1000) {
230
snd_printk(KERN_WARNING
231
"emu10k1:I2C:timeout status=0x%x\n",
236
//Read back and see if the transaction is successful
237
if ((status & I2C_A_ADC_ABORT) == 0)
242
snd_printk(KERN_ERR "Writing to ADC failed!\n");
243
snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
249
spin_unlock(&emu->i2c_lock);
253
int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
259
reg += 0x40; /* 0x40 upwards are registers. */
260
if (value > 0x3f) /* 0 to 0x3f are values */
262
spin_lock_irqsave(&emu->emu_lock, flags);
263
outl(reg, emu->port + A_IOCFG);
265
outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
267
outl(value, emu->port + A_IOCFG);
269
outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
270
spin_unlock_irqrestore(&emu->emu_lock, flags);
275
int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
280
reg += 0x40; /* 0x40 upwards are registers. */
281
spin_lock_irqsave(&emu->emu_lock, flags);
282
outl(reg, emu->port + A_IOCFG);
284
outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
286
*value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
287
spin_unlock_irqrestore(&emu->emu_lock, flags);
292
/* Each Destination has one and only one Source,
293
* but one Source can feed any number of Destinations simultaneously.
295
int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
297
snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
298
snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
299
snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
300
snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
305
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
310
spin_lock_irqsave(&emu->emu_lock, flags);
311
enable = inl(emu->port + INTE) | intrenb;
312
outl(enable, emu->port + INTE);
313
spin_unlock_irqrestore(&emu->emu_lock, flags);
316
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
321
spin_lock_irqsave(&emu->emu_lock, flags);
322
enable = inl(emu->port + INTE) & ~intrenb;
323
outl(enable, emu->port + INTE);
324
spin_unlock_irqrestore(&emu->emu_lock, flags);
327
void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
332
spin_lock_irqsave(&emu->emu_lock, flags);
333
/* voice interrupt */
334
if (voicenum >= 32) {
335
outl(CLIEH << 16, emu->port + PTR);
336
val = inl(emu->port + DATA);
337
val |= 1 << (voicenum - 32);
339
outl(CLIEL << 16, emu->port + PTR);
340
val = inl(emu->port + DATA);
341
val |= 1 << voicenum;
343
outl(val, emu->port + DATA);
344
spin_unlock_irqrestore(&emu->emu_lock, flags);
347
void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
352
spin_lock_irqsave(&emu->emu_lock, flags);
353
/* voice interrupt */
354
if (voicenum >= 32) {
355
outl(CLIEH << 16, emu->port + PTR);
356
val = inl(emu->port + DATA);
357
val &= ~(1 << (voicenum - 32));
359
outl(CLIEL << 16, emu->port + PTR);
360
val = inl(emu->port + DATA);
361
val &= ~(1 << voicenum);
363
outl(val, emu->port + DATA);
364
spin_unlock_irqrestore(&emu->emu_lock, flags);
367
void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
371
spin_lock_irqsave(&emu->emu_lock, flags);
372
/* voice interrupt */
373
if (voicenum >= 32) {
374
outl(CLIPH << 16, emu->port + PTR);
375
voicenum = 1 << (voicenum - 32);
377
outl(CLIPL << 16, emu->port + PTR);
378
voicenum = 1 << voicenum;
380
outl(voicenum, emu->port + DATA);
381
spin_unlock_irqrestore(&emu->emu_lock, flags);
384
void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
389
spin_lock_irqsave(&emu->emu_lock, flags);
390
/* voice interrupt */
391
if (voicenum >= 32) {
392
outl(HLIEH << 16, emu->port + PTR);
393
val = inl(emu->port + DATA);
394
val |= 1 << (voicenum - 32);
396
outl(HLIEL << 16, emu->port + PTR);
397
val = inl(emu->port + DATA);
398
val |= 1 << voicenum;
400
outl(val, emu->port + DATA);
401
spin_unlock_irqrestore(&emu->emu_lock, flags);
404
void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
409
spin_lock_irqsave(&emu->emu_lock, flags);
410
/* voice interrupt */
411
if (voicenum >= 32) {
412
outl(HLIEH << 16, emu->port + PTR);
413
val = inl(emu->port + DATA);
414
val &= ~(1 << (voicenum - 32));
416
outl(HLIEL << 16, emu->port + PTR);
417
val = inl(emu->port + DATA);
418
val &= ~(1 << voicenum);
420
outl(val, emu->port + DATA);
421
spin_unlock_irqrestore(&emu->emu_lock, flags);
424
void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
428
spin_lock_irqsave(&emu->emu_lock, flags);
429
/* voice interrupt */
430
if (voicenum >= 32) {
431
outl(HLIPH << 16, emu->port + PTR);
432
voicenum = 1 << (voicenum - 32);
434
outl(HLIPL << 16, emu->port + PTR);
435
voicenum = 1 << voicenum;
437
outl(voicenum, emu->port + DATA);
438
spin_unlock_irqrestore(&emu->emu_lock, flags);
441
void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
446
spin_lock_irqsave(&emu->emu_lock, flags);
447
/* voice interrupt */
448
if (voicenum >= 32) {
449
outl(SOLEH << 16, emu->port + PTR);
450
sol = inl(emu->port + DATA);
451
sol |= 1 << (voicenum - 32);
453
outl(SOLEL << 16, emu->port + PTR);
454
sol = inl(emu->port + DATA);
455
sol |= 1 << voicenum;
457
outl(sol, emu->port + DATA);
458
spin_unlock_irqrestore(&emu->emu_lock, flags);
461
void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
466
spin_lock_irqsave(&emu->emu_lock, flags);
467
/* voice interrupt */
468
if (voicenum >= 32) {
469
outl(SOLEH << 16, emu->port + PTR);
470
sol = inl(emu->port + DATA);
471
sol &= ~(1 << (voicenum - 32));
473
outl(SOLEL << 16, emu->port + PTR);
474
sol = inl(emu->port + DATA);
475
sol &= ~(1 << voicenum);
477
outl(sol, emu->port + DATA);
478
spin_unlock_irqrestore(&emu->emu_lock, flags);
481
void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
483
volatile unsigned count;
484
unsigned int newtime = 0, curtime;
486
curtime = inl(emu->port + WC) >> 6;
489
while (count++ < 16384) {
490
newtime = inl(emu->port + WC) >> 6;
491
if (newtime != curtime)
500
unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
502
struct snd_emu10k1 *emu = ac97->private_data;
506
spin_lock_irqsave(&emu->emu_lock, flags);
507
outb(reg, emu->port + AC97ADDRESS);
508
val = inw(emu->port + AC97DATA);
509
spin_unlock_irqrestore(&emu->emu_lock, flags);
513
void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
515
struct snd_emu10k1 *emu = ac97->private_data;
518
spin_lock_irqsave(&emu->emu_lock, flags);
519
outb(reg, emu->port + AC97ADDRESS);
520
outw(data, emu->port + AC97DATA);
521
spin_unlock_irqrestore(&emu->emu_lock, flags);
525
* convert rate to pitch
528
unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
530
static u32 logMagTable[128] = {
531
0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
532
0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
533
0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
534
0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
535
0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
536
0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
537
0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
538
0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
539
0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
540
0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
541
0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
542
0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
543
0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
544
0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
545
0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
546
0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
548
static char logSlopeTable[128] = {
549
0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
550
0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
551
0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
552
0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
553
0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
554
0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
555
0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
556
0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
557
0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
558
0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
559
0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
560
0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
561
0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
562
0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
563
0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
564
0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
569
return 0; /* Bail out if no leading "1" */
570
rate *= 11185; /* Scale 48000 to 0x20002380 */
571
for (i = 31; i > 0; i--) {
572
if (rate & 0x80000000) { /* Detect leading "1" */
573
return (((unsigned int) (i - 15) << 20) +
574
logMagTable[0x7f & (rate >> 24)] +
575
(0x7f & (rate >> 17)) *
576
logSlopeTable[0x7f & (rate >> 24)]);
581
return 0; /* Should never reach this point */