blob: 5ef7080e14d090c2c83ea5b6edb0705f0e09a249 [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
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +000073 if (!emu) {
74 snd_printk(KERN_ERR "ptr_write: emu is null!\n");
75 dump_stack();
76 return;
77 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
79 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
80
81 if (reg & 0xff000000) {
82 unsigned char size, offset;
83
84 size = (reg >> 24) & 0x3f;
85 offset = (reg >> 16) & 0x1f;
86 mask = ((1 << size) - 1) << offset;
87 data = (data << offset) & mask;
88
89 spin_lock_irqsave(&emu->emu_lock, flags);
90 outl(regptr, emu->port + PTR);
91 data |= inl(emu->port + DATA) & ~mask;
92 outl(data, emu->port + DATA);
93 spin_unlock_irqrestore(&emu->emu_lock, flags);
94 } else {
95 spin_lock_irqsave(&emu->emu_lock, flags);
96 outl(regptr, emu->port + PTR);
97 outl(data, emu->port + DATA);
98 spin_unlock_irqrestore(&emu->emu_lock, flags);
99 }
100}
101
Takashi Iwai2dd31de2006-04-28 15:13:39 +0200102EXPORT_SYMBOL(snd_emu10k1_ptr_write);
103
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100104unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 unsigned int reg,
106 unsigned int chn)
107{
108 unsigned long flags;
109 unsigned int regptr, val;
110
111 regptr = (reg << 16) | chn;
112
113 spin_lock_irqsave(&emu->emu_lock, flags);
114 outl(regptr, emu->port + 0x20 + PTR);
115 val = inl(emu->port + 0x20 + DATA);
116 spin_unlock_irqrestore(&emu->emu_lock, flags);
117 return val;
118}
119
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100120void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 unsigned int reg,
122 unsigned int chn,
123 unsigned int data)
124{
125 unsigned int regptr;
126 unsigned long flags;
127
128 regptr = (reg << 16) | chn;
129
130 spin_lock_irqsave(&emu->emu_lock, flags);
131 outl(regptr, emu->port + 0x20 + PTR);
132 outl(data, emu->port + 0x20 + DATA);
133 spin_unlock_irqrestore(&emu->emu_lock, flags);
134}
135
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100136int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
137 unsigned int data)
138{
139 unsigned int reset, set;
140 unsigned int reg, tmp;
141 int n, result;
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000142 int err = 0;
143
144 /* This function is not re-entrant, so protect against it. */
145 spin_lock(&emu->spi_lock);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100146 if (emu->card_capabilities->ca0108_chip)
147 reg = 0x3c; /* PTR20, reg 0x3c */
148 else {
149 /* For other chip types the SPI register
150 * is currently unknown. */
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000151 err = 1;
152 goto spi_write_exit;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100153 }
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000154 if (data > 0xffff) {
155 /* Only 16bit values allowed */
156 err = 1;
157 goto spi_write_exit;
158 }
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100159
160 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100161 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100162 set = reset | 0x10000; /* Set xxx1xxxx */
163 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
164 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
165 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
166 result = 1;
167 /* Wait for status bit to return to 0 */
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100168 for (n = 0; n < 100; n++) {
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100169 udelay(10);
170 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
171 if (!(tmp & 0x10000)) {
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100172 result = 0;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100173 break;
174 }
175 }
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000176 if (result) {
177 /* Timed out */
178 err = 1;
179 goto spi_write_exit;
180 }
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100181 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
182 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000183 err = 0;
184spi_write_exit:
185 spin_unlock(&emu->spi_lock);
186 return err;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100187}
188
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000189/* The ADC does not support i2c read, so only write is implemented */
190int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
191 u32 reg,
192 u32 value)
193{
194 u32 tmp;
195 int timeout = 0;
196 int status;
197 int retry;
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000198 int err = 0;
199
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000200 if ((reg > 0x7f) || (value > 0x1ff)) {
201 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
202 return -EINVAL;
203 }
204
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000205 /* This function is not re-entrant, so protect against it. */
206 spin_lock(&emu->i2c_lock);
207
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000208 tmp = reg << 25 | value << 16;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000209
210 /* This controls the I2C connected to the WM8775 ADC Codec */
211 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
212 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
213
214 for (retry = 0; retry < 10; retry++) {
215 /* Send the data to i2c */
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000216 tmp = 0;
217 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
218 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
219
220 /* Wait till the transaction ends */
221 while (1) {
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000222 mdelay(1);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000223 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000224 timeout++;
225 if ((status & I2C_A_ADC_START) == 0)
226 break;
227
228 if (timeout > 1000) {
Takashi Iwai28a97c12009-02-05 16:08:14 +0100229 snd_printk(KERN_WARNING
230 "emu10k1:I2C:timeout status=0x%x\n",
231 status);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000232 break;
233 }
234 }
235 //Read back and see if the transaction is successful
236 if ((status & I2C_A_ADC_ABORT) == 0)
237 break;
238 }
239
240 if (retry == 10) {
241 snd_printk(KERN_ERR "Writing to ADC failed!\n");
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000242 snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
243 status, reg, value);
244 /* dump_stack(); */
245 err = -EINVAL;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000246 }
247
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000248 spin_unlock(&emu->i2c_lock);
249 return err;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000250}
251
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100252int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100253{
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000254 unsigned long flags;
255
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100256 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100257 return 1;
258 reg += 0x40; /* 0x40 upwards are registers. */
Roel Kluin84ed1a12009-10-23 16:03:08 +0200259 if (value > 0x3f) /* 0 to 0x3f are values */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100260 return 1;
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000261 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100262 outl(reg, emu->port + A_IOCFG);
263 udelay(10);
264 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
265 udelay(10);
266 outl(value, emu->port + A_IOCFG);
267 udelay(10);
268 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000269 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100270
271 return 0;
272}
273
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100274int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100275{
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000276 unsigned long flags;
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100277 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100278 return 1;
279 reg += 0x40; /* 0x40 upwards are registers. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000280 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100281 outl(reg, emu->port + A_IOCFG);
282 udelay(10);
283 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
284 udelay(10);
285 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000286 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100287
288 return 0;
289}
290
291/* Each Destination has one and only one Source,
292 * but one Source can feed any number of Destinations simultaneously.
293 */
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100294int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100295{
296 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
297 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
298 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
299 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
300
301 return 0;
302}
303
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100304void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
306 unsigned long flags;
307 unsigned int enable;
308
309 spin_lock_irqsave(&emu->emu_lock, flags);
310 enable = inl(emu->port + INTE) | intrenb;
311 outl(enable, emu->port + INTE);
312 spin_unlock_irqrestore(&emu->emu_lock, flags);
313}
314
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100315void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 unsigned long flags;
318 unsigned int enable;
319
320 spin_lock_irqsave(&emu->emu_lock, flags);
321 enable = inl(emu->port + INTE) & ~intrenb;
322 outl(enable, emu->port + INTE);
323 spin_unlock_irqrestore(&emu->emu_lock, flags);
324}
325
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100326void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 unsigned long flags;
329 unsigned int val;
330
331 spin_lock_irqsave(&emu->emu_lock, flags);
332 /* voice interrupt */
333 if (voicenum >= 32) {
334 outl(CLIEH << 16, emu->port + PTR);
335 val = inl(emu->port + DATA);
336 val |= 1 << (voicenum - 32);
337 } else {
338 outl(CLIEL << 16, emu->port + PTR);
339 val = inl(emu->port + DATA);
340 val |= 1 << voicenum;
341 }
342 outl(val, emu->port + DATA);
343 spin_unlock_irqrestore(&emu->emu_lock, flags);
344}
345
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100346void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 unsigned long flags;
349 unsigned int val;
350
351 spin_lock_irqsave(&emu->emu_lock, flags);
352 /* voice interrupt */
353 if (voicenum >= 32) {
354 outl(CLIEH << 16, emu->port + PTR);
355 val = inl(emu->port + DATA);
356 val &= ~(1 << (voicenum - 32));
357 } else {
358 outl(CLIEL << 16, emu->port + PTR);
359 val = inl(emu->port + DATA);
360 val &= ~(1 << voicenum);
361 }
362 outl(val, emu->port + DATA);
363 spin_unlock_irqrestore(&emu->emu_lock, flags);
364}
365
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100366void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 unsigned long flags;
369
370 spin_lock_irqsave(&emu->emu_lock, flags);
371 /* voice interrupt */
372 if (voicenum >= 32) {
373 outl(CLIPH << 16, emu->port + PTR);
374 voicenum = 1 << (voicenum - 32);
375 } else {
376 outl(CLIPL << 16, emu->port + PTR);
377 voicenum = 1 << voicenum;
378 }
379 outl(voicenum, emu->port + DATA);
380 spin_unlock_irqrestore(&emu->emu_lock, flags);
381}
382
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100383void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 unsigned long flags;
386 unsigned int val;
387
388 spin_lock_irqsave(&emu->emu_lock, flags);
389 /* voice interrupt */
390 if (voicenum >= 32) {
391 outl(HLIEH << 16, emu->port + PTR);
392 val = inl(emu->port + DATA);
393 val |= 1 << (voicenum - 32);
394 } else {
395 outl(HLIEL << 16, emu->port + PTR);
396 val = inl(emu->port + DATA);
397 val |= 1 << voicenum;
398 }
399 outl(val, emu->port + DATA);
400 spin_unlock_irqrestore(&emu->emu_lock, flags);
401}
402
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100403void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
405 unsigned long flags;
406 unsigned int val;
407
408 spin_lock_irqsave(&emu->emu_lock, flags);
409 /* voice interrupt */
410 if (voicenum >= 32) {
411 outl(HLIEH << 16, emu->port + PTR);
412 val = inl(emu->port + DATA);
413 val &= ~(1 << (voicenum - 32));
414 } else {
415 outl(HLIEL << 16, emu->port + PTR);
416 val = inl(emu->port + DATA);
417 val &= ~(1 << voicenum);
418 }
419 outl(val, emu->port + DATA);
420 spin_unlock_irqrestore(&emu->emu_lock, flags);
421}
422
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100423void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424{
425 unsigned long flags;
426
427 spin_lock_irqsave(&emu->emu_lock, flags);
428 /* voice interrupt */
429 if (voicenum >= 32) {
430 outl(HLIPH << 16, emu->port + PTR);
431 voicenum = 1 << (voicenum - 32);
432 } else {
433 outl(HLIPL << 16, emu->port + PTR);
434 voicenum = 1 << voicenum;
435 }
436 outl(voicenum, emu->port + DATA);
437 spin_unlock_irqrestore(&emu->emu_lock, flags);
438}
439
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100440void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
442 unsigned long flags;
443 unsigned int sol;
444
445 spin_lock_irqsave(&emu->emu_lock, flags);
446 /* voice interrupt */
447 if (voicenum >= 32) {
448 outl(SOLEH << 16, emu->port + PTR);
449 sol = inl(emu->port + DATA);
450 sol |= 1 << (voicenum - 32);
451 } else {
452 outl(SOLEL << 16, emu->port + PTR);
453 sol = inl(emu->port + DATA);
454 sol |= 1 << voicenum;
455 }
456 outl(sol, emu->port + DATA);
457 spin_unlock_irqrestore(&emu->emu_lock, flags);
458}
459
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100460void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 unsigned long flags;
463 unsigned int sol;
464
465 spin_lock_irqsave(&emu->emu_lock, flags);
466 /* voice interrupt */
467 if (voicenum >= 32) {
468 outl(SOLEH << 16, emu->port + PTR);
469 sol = inl(emu->port + DATA);
470 sol &= ~(1 << (voicenum - 32));
471 } else {
472 outl(SOLEL << 16, emu->port + PTR);
473 sol = inl(emu->port + DATA);
474 sol &= ~(1 << voicenum);
475 }
476 outl(sol, emu->port + DATA);
477 spin_unlock_irqrestore(&emu->emu_lock, flags);
478}
479
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100480void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
482 volatile unsigned count;
483 unsigned int newtime = 0, curtime;
484
485 curtime = inl(emu->port + WC) >> 6;
486 while (wait-- > 0) {
487 count = 0;
488 while (count++ < 16384) {
489 newtime = inl(emu->port + WC) >> 6;
490 if (newtime != curtime)
491 break;
492 }
Roel Kluin5a47fa32009-04-16 23:54:04 +0200493 if (count > 16384)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 break;
495 curtime = newtime;
496 }
497}
498
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100499unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100501 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 unsigned long flags;
503 unsigned short val;
504
505 spin_lock_irqsave(&emu->emu_lock, flags);
506 outb(reg, emu->port + AC97ADDRESS);
507 val = inw(emu->port + AC97DATA);
508 spin_unlock_irqrestore(&emu->emu_lock, flags);
509 return val;
510}
511
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100512void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100514 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 unsigned long flags;
516
517 spin_lock_irqsave(&emu->emu_lock, flags);
518 outb(reg, emu->port + AC97ADDRESS);
519 outw(data, emu->port + AC97DATA);
520 spin_unlock_irqrestore(&emu->emu_lock, flags);
521}
522
523/*
524 * convert rate to pitch
525 */
526
527unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
528{
529 static u32 logMagTable[128] = {
530 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
531 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
532 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
533 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
534 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
535 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
536 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
537 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
538 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
539 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
540 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
541 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
542 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
543 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
544 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
545 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
546 };
547 static char logSlopeTable[128] = {
548 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
549 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
550 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
551 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
552 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
553 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
554 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
555 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
556 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
557 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
558 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
559 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
560 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
561 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
562 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
563 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
564 };
565 int i;
566
567 if (rate == 0)
568 return 0; /* Bail out if no leading "1" */
569 rate *= 11185; /* Scale 48000 to 0x20002380 */
570 for (i = 31; i > 0; i--) {
571 if (rate & 0x80000000) { /* Detect leading "1" */
572 return (((unsigned int) (i - 15) << 20) +
573 logMagTable[0x7f & (rate >> 24)] +
574 (0x7f & (rate >> 17)) *
575 logSlopeTable[0x7f & (rate >> 24)]);
576 }
577 rate <<= 1;
578 }
579
580 return 0; /* Should never reach this point */
581}
582