blob: a02638350a0ac40ad37f144a727c1d351bf2fc47 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02002 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Creative Labs, Inc.
4 * Routines for control of EMU10K1 chips
5 *
6 * BUGS:
7 * --
8 *
9 * TODO:
10 * --
11 *
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.
16 *
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.
21 *
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
25 *
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/time.h>
29#include <sound/core.h>
30#include <sound/emu10k1.h>
James Courtier-Dutton27fe8642005-12-21 15:06:08 +010031#include <linux/delay.h>
James Courtier-Dutton184c1e22006-12-06 15:58:02 +000032#include "p17v.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Takashi Iwaieb4698f2005-11-17 14:50:13 +010034unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
36 unsigned long flags;
37 unsigned int regptr, val;
38 unsigned int mask;
39
40 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
41 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
42
43 if (reg & 0xff000000) {
44 unsigned char size, offset;
45
46 size = (reg >> 24) & 0x3f;
47 offset = (reg >> 16) & 0x1f;
48 mask = ((1 << size) - 1) << offset;
49
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);
54
55 return (val & mask) >> offset;
56 } else {
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);
61 return val;
62 }
63}
64
Takashi Iwai2dd31de2006-04-28 15:13:39 +020065EXPORT_SYMBOL(snd_emu10k1_ptr_read);
66
Takashi Iwaieb4698f2005-11-17 14:50:13 +010067void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068{
69 unsigned int regptr;
70 unsigned long flags;
71 unsigned int mask;
72
73 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
74 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
75
76 if (reg & 0xff000000) {
77 unsigned char size, offset;
78
79 size = (reg >> 24) & 0x3f;
80 offset = (reg >> 16) & 0x1f;
81 mask = ((1 << size) - 1) << offset;
82 data = (data << offset) & mask;
83
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);
89 } else {
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);
94 }
95}
96
Takashi Iwai2dd31de2006-04-28 15:13:39 +020097EXPORT_SYMBOL(snd_emu10k1_ptr_write);
98
Takashi Iwaieb4698f2005-11-17 14:50:13 +010099unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 unsigned int reg,
101 unsigned int chn)
102{
103 unsigned long flags;
104 unsigned int regptr, val;
105
106 regptr = (reg << 16) | chn;
107
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);
112 return val;
113}
114
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100115void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 unsigned int reg,
117 unsigned int chn,
118 unsigned int data)
119{
120 unsigned int regptr;
121 unsigned long flags;
122
123 regptr = (reg << 16) | chn;
124
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);
129}
130
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100131int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
132 unsigned int data)
133{
134 unsigned int reset, set;
135 unsigned int reg, tmp;
136 int n, result;
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100137 if (emu->card_capabilities->ca0108_chip)
138 reg = 0x3c; /* PTR20, reg 0x3c */
139 else {
140 /* For other chip types the SPI register
141 * is currently unknown. */
142 return 1;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100143 }
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100144 if (data > 0xffff) /* Only 16bit values allowed */
145 return 1;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100146
147 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100148 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100149 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);
153 result = 1;
154 /* Wait for status bit to return to 0 */
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100155 for (n = 0; n < 100; n++) {
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100156 udelay(10);
157 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
158 if (!(tmp & 0x10000)) {
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100159 result = 0;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100160 break;
161 }
162 }
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100163 if (result) /* Timed out */
164 return 1;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
167 return 0;
168}
169
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000170/* The ADC does not support i2c read, so only write is implemented */
171int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
172 u32 reg,
173 u32 value)
174{
175 u32 tmp;
176 int timeout = 0;
177 int status;
178 int retry;
179 if ((reg > 0x7f) || (value > 0x1ff)) {
180 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
181 return -EINVAL;
182 }
183
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); */
188
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 */
192
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);
197 tmp = 0;
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);
200
201 /* Wait till the transaction ends */
202 while (1) {
203 udelay(10);
204 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
205 // snd_printk("I2C:status=0x%x\n", status);
206 timeout++;
207 if ((status & I2C_A_ADC_START) == 0)
208 break;
209
210 if (timeout > 1000) {
211 snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
212 break;
213 }
214 }
215 //Read back and see if the transaction is successful
216 if ((status & I2C_A_ADC_ABORT) == 0)
217 break;
218 }
219
220 if (retry == 10) {
221 snd_printk(KERN_ERR "Writing to ADC failed!\n");
222 return -EINVAL;
223 }
224
225 return 0;
226}
227
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100228int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100229{
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000230 unsigned long flags;
231
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100232 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100233 return 1;
234 reg += 0x40; /* 0x40 upwards are registers. */
235 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
236 return 1;
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000237 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100238 outl(reg, emu->port + A_IOCFG);
239 udelay(10);
240 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
241 udelay(10);
242 outl(value, emu->port + A_IOCFG);
243 udelay(10);
244 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000245 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100246
247 return 0;
248}
249
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100250int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100251{
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000252 unsigned long flags;
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100253 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100254 return 1;
255 reg += 0x40; /* 0x40 upwards are registers. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000256 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100257 outl(reg, emu->port + A_IOCFG);
258 udelay(10);
259 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
260 udelay(10);
261 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000262 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100263
264 return 0;
265}
266
267/* Each Destination has one and only one Source,
268 * but one Source can feed any number of Destinations simultaneously.
269 */
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100270int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100271{
272 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
273 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
274 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
275 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
276
277 return 0;
278}
279
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100280void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 unsigned long flags;
283 unsigned int enable;
284
285 spin_lock_irqsave(&emu->emu_lock, flags);
286 enable = inl(emu->port + INTE) | intrenb;
287 outl(enable, emu->port + INTE);
288 spin_unlock_irqrestore(&emu->emu_lock, flags);
289}
290
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100291void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
293 unsigned long flags;
294 unsigned int enable;
295
296 spin_lock_irqsave(&emu->emu_lock, flags);
297 enable = inl(emu->port + INTE) & ~intrenb;
298 outl(enable, emu->port + INTE);
299 spin_unlock_irqrestore(&emu->emu_lock, flags);
300}
301
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100302void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 unsigned long flags;
305 unsigned int val;
306
307 spin_lock_irqsave(&emu->emu_lock, flags);
308 /* voice interrupt */
309 if (voicenum >= 32) {
310 outl(CLIEH << 16, emu->port + PTR);
311 val = inl(emu->port + DATA);
312 val |= 1 << (voicenum - 32);
313 } else {
314 outl(CLIEL << 16, emu->port + PTR);
315 val = inl(emu->port + DATA);
316 val |= 1 << voicenum;
317 }
318 outl(val, emu->port + DATA);
319 spin_unlock_irqrestore(&emu->emu_lock, flags);
320}
321
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100322void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
324 unsigned long flags;
325 unsigned int val;
326
327 spin_lock_irqsave(&emu->emu_lock, flags);
328 /* voice interrupt */
329 if (voicenum >= 32) {
330 outl(CLIEH << 16, emu->port + PTR);
331 val = inl(emu->port + DATA);
332 val &= ~(1 << (voicenum - 32));
333 } else {
334 outl(CLIEL << 16, emu->port + PTR);
335 val = inl(emu->port + DATA);
336 val &= ~(1 << voicenum);
337 }
338 outl(val, emu->port + DATA);
339 spin_unlock_irqrestore(&emu->emu_lock, flags);
340}
341
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100342void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
344 unsigned long flags;
345
346 spin_lock_irqsave(&emu->emu_lock, flags);
347 /* voice interrupt */
348 if (voicenum >= 32) {
349 outl(CLIPH << 16, emu->port + PTR);
350 voicenum = 1 << (voicenum - 32);
351 } else {
352 outl(CLIPL << 16, emu->port + PTR);
353 voicenum = 1 << voicenum;
354 }
355 outl(voicenum, emu->port + DATA);
356 spin_unlock_irqrestore(&emu->emu_lock, flags);
357}
358
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100359void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 unsigned long flags;
362 unsigned int val;
363
364 spin_lock_irqsave(&emu->emu_lock, flags);
365 /* voice interrupt */
366 if (voicenum >= 32) {
367 outl(HLIEH << 16, emu->port + PTR);
368 val = inl(emu->port + DATA);
369 val |= 1 << (voicenum - 32);
370 } else {
371 outl(HLIEL << 16, emu->port + PTR);
372 val = inl(emu->port + DATA);
373 val |= 1 << voicenum;
374 }
375 outl(val, emu->port + DATA);
376 spin_unlock_irqrestore(&emu->emu_lock, flags);
377}
378
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100379void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 unsigned long flags;
382 unsigned int val;
383
384 spin_lock_irqsave(&emu->emu_lock, flags);
385 /* voice interrupt */
386 if (voicenum >= 32) {
387 outl(HLIEH << 16, emu->port + PTR);
388 val = inl(emu->port + DATA);
389 val &= ~(1 << (voicenum - 32));
390 } else {
391 outl(HLIEL << 16, emu->port + PTR);
392 val = inl(emu->port + DATA);
393 val &= ~(1 << voicenum);
394 }
395 outl(val, emu->port + DATA);
396 spin_unlock_irqrestore(&emu->emu_lock, flags);
397}
398
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100399void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
401 unsigned long flags;
402
403 spin_lock_irqsave(&emu->emu_lock, flags);
404 /* voice interrupt */
405 if (voicenum >= 32) {
406 outl(HLIPH << 16, emu->port + PTR);
407 voicenum = 1 << (voicenum - 32);
408 } else {
409 outl(HLIPL << 16, emu->port + PTR);
410 voicenum = 1 << voicenum;
411 }
412 outl(voicenum, emu->port + DATA);
413 spin_unlock_irqrestore(&emu->emu_lock, flags);
414}
415
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100416void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 unsigned long flags;
419 unsigned int sol;
420
421 spin_lock_irqsave(&emu->emu_lock, flags);
422 /* voice interrupt */
423 if (voicenum >= 32) {
424 outl(SOLEH << 16, emu->port + PTR);
425 sol = inl(emu->port + DATA);
426 sol |= 1 << (voicenum - 32);
427 } else {
428 outl(SOLEL << 16, emu->port + PTR);
429 sol = inl(emu->port + DATA);
430 sol |= 1 << voicenum;
431 }
432 outl(sol, emu->port + DATA);
433 spin_unlock_irqrestore(&emu->emu_lock, flags);
434}
435
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100436void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 unsigned long flags;
439 unsigned int sol;
440
441 spin_lock_irqsave(&emu->emu_lock, flags);
442 /* voice interrupt */
443 if (voicenum >= 32) {
444 outl(SOLEH << 16, emu->port + PTR);
445 sol = inl(emu->port + DATA);
446 sol &= ~(1 << (voicenum - 32));
447 } else {
448 outl(SOLEL << 16, emu->port + PTR);
449 sol = inl(emu->port + DATA);
450 sol &= ~(1 << voicenum);
451 }
452 outl(sol, emu->port + DATA);
453 spin_unlock_irqrestore(&emu->emu_lock, flags);
454}
455
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100456void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
458 volatile unsigned count;
459 unsigned int newtime = 0, curtime;
460
461 curtime = inl(emu->port + WC) >> 6;
462 while (wait-- > 0) {
463 count = 0;
464 while (count++ < 16384) {
465 newtime = inl(emu->port + WC) >> 6;
466 if (newtime != curtime)
467 break;
468 }
469 if (count >= 16384)
470 break;
471 curtime = newtime;
472 }
473}
474
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100475unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100477 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 unsigned long flags;
479 unsigned short val;
480
481 spin_lock_irqsave(&emu->emu_lock, flags);
482 outb(reg, emu->port + AC97ADDRESS);
483 val = inw(emu->port + AC97DATA);
484 spin_unlock_irqrestore(&emu->emu_lock, flags);
485 return val;
486}
487
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100488void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100490 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 unsigned long flags;
492
493 spin_lock_irqsave(&emu->emu_lock, flags);
494 outb(reg, emu->port + AC97ADDRESS);
495 outw(data, emu->port + AC97DATA);
496 spin_unlock_irqrestore(&emu->emu_lock, flags);
497}
498
499/*
500 * convert rate to pitch
501 */
502
503unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
504{
505 static u32 logMagTable[128] = {
506 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
507 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
508 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
509 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
510 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
511 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
512 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
513 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
514 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
515 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
516 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
517 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
518 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
519 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
520 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
521 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
522 };
523 static char logSlopeTable[128] = {
524 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
525 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
526 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
527 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
528 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
529 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
530 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
531 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
532 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
533 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
534 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
535 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
536 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
537 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
538 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
539 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
540 };
541 int i;
542
543 if (rate == 0)
544 return 0; /* Bail out if no leading "1" */
545 rate *= 11185; /* Scale 48000 to 0x20002380 */
546 for (i = 31; i > 0; i--) {
547 if (rate & 0x80000000) { /* Detect leading "1" */
548 return (((unsigned int) (i - 15) << 20) +
549 logMagTable[0x7f & (rate >> 24)] +
550 (0x7f & (rate >> 17)) *
551 logSlopeTable[0x7f & (rate >> 24)]);
552 }
553 rate <<= 1;
554 }
555
556 return 0; /* Should never reach this point */
557}
558