blob: e4fba49fee4a9cd633e0968203832ac7a1dbc4fe [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>
Paul Gortmakerd81a6d72011-09-22 09:34:58 -040032#include <linux/export.h>
James Courtier-Dutton184c1e22006-12-06 15:58:02 +000033#include "p17v.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Takashi Iwaieb4698f2005-11-17 14:50:13 +010035unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036{
37 unsigned long flags;
38 unsigned int regptr, val;
39 unsigned int mask;
40
41 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
42 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
43
44 if (reg & 0xff000000) {
45 unsigned char size, offset;
46
47 size = (reg >> 24) & 0x3f;
48 offset = (reg >> 16) & 0x1f;
49 mask = ((1 << size) - 1) << offset;
50
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);
55
56 return (val & mask) >> offset;
57 } else {
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);
62 return val;
63 }
64}
65
Takashi Iwai2dd31de2006-04-28 15:13:39 +020066EXPORT_SYMBOL(snd_emu10k1_ptr_read);
67
Takashi Iwaieb4698f2005-11-17 14:50:13 +010068void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
70 unsigned int regptr;
71 unsigned long flags;
72 unsigned int mask;
73
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +000074 if (!emu) {
75 snd_printk(KERN_ERR "ptr_write: emu is null!\n");
76 dump_stack();
77 return;
78 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
80 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
81
82 if (reg & 0xff000000) {
83 unsigned char size, offset;
84
85 size = (reg >> 24) & 0x3f;
86 offset = (reg >> 16) & 0x1f;
87 mask = ((1 << size) - 1) << offset;
88 data = (data << offset) & mask;
89
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);
95 } else {
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);
100 }
101}
102
Takashi Iwai2dd31de2006-04-28 15:13:39 +0200103EXPORT_SYMBOL(snd_emu10k1_ptr_write);
104
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100105unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 unsigned int reg,
107 unsigned int chn)
108{
109 unsigned long flags;
110 unsigned int regptr, val;
111
112 regptr = (reg << 16) | chn;
113
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);
118 return val;
119}
120
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100121void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 unsigned int reg,
123 unsigned int chn,
124 unsigned int data)
125{
126 unsigned int regptr;
127 unsigned long flags;
128
129 regptr = (reg << 16) | chn;
130
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);
135}
136
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100137int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
138 unsigned int data)
139{
140 unsigned int reset, set;
141 unsigned int reg, tmp;
142 int n, result;
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000143 int err = 0;
144
145 /* This function is not re-entrant, so protect against it. */
146 spin_lock(&emu->spi_lock);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100147 if (emu->card_capabilities->ca0108_chip)
148 reg = 0x3c; /* PTR20, reg 0x3c */
149 else {
150 /* For other chip types the SPI register
151 * is currently unknown. */
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000152 err = 1;
153 goto spi_write_exit;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100154 }
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000155 if (data > 0xffff) {
156 /* Only 16bit values allowed */
157 err = 1;
158 goto spi_write_exit;
159 }
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100160
161 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100162 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100163 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);
167 result = 1;
168 /* Wait for status bit to return to 0 */
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100169 for (n = 0; n < 100; n++) {
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100170 udelay(10);
171 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
172 if (!(tmp & 0x10000)) {
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100173 result = 0;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100174 break;
175 }
176 }
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000177 if (result) {
178 /* Timed out */
179 err = 1;
180 goto spi_write_exit;
181 }
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100182 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
183 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000184 err = 0;
185spi_write_exit:
186 spin_unlock(&emu->spi_lock);
187 return err;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100188}
189
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000190/* The ADC does not support i2c read, so only write is implemented */
191int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
192 u32 reg,
193 u32 value)
194{
195 u32 tmp;
196 int timeout = 0;
197 int status;
198 int retry;
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000199 int err = 0;
200
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000201 if ((reg > 0x7f) || (value > 0x1ff)) {
202 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
203 return -EINVAL;
204 }
205
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000206 /* This function is not re-entrant, so protect against it. */
207 spin_lock(&emu->i2c_lock);
208
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000209 tmp = reg << 25 | value << 16;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000210
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 */
214
215 for (retry = 0; retry < 10; retry++) {
216 /* Send the data to i2c */
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000217 tmp = 0;
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);
220
221 /* Wait till the transaction ends */
222 while (1) {
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000223 mdelay(1);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000224 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000225 timeout++;
226 if ((status & I2C_A_ADC_START) == 0)
227 break;
228
229 if (timeout > 1000) {
Takashi Iwai28a97c12009-02-05 16:08:14 +0100230 snd_printk(KERN_WARNING
231 "emu10k1:I2C:timeout status=0x%x\n",
232 status);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000233 break;
234 }
235 }
236 //Read back and see if the transaction is successful
237 if ((status & I2C_A_ADC_ABORT) == 0)
238 break;
239 }
240
241 if (retry == 10) {
242 snd_printk(KERN_ERR "Writing to ADC failed!\n");
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000243 snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
244 status, reg, value);
245 /* dump_stack(); */
246 err = -EINVAL;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000247 }
248
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000249 spin_unlock(&emu->i2c_lock);
250 return err;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000251}
252
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100253int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100254{
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000255 unsigned long flags;
256
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100257 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100258 return 1;
259 reg += 0x40; /* 0x40 upwards are registers. */
Roel Kluin84ed1a12009-10-23 16:03:08 +0200260 if (value > 0x3f) /* 0 to 0x3f are values */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100261 return 1;
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000262 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100263 outl(reg, emu->port + A_IOCFG);
264 udelay(10);
265 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
266 udelay(10);
267 outl(value, emu->port + A_IOCFG);
268 udelay(10);
269 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000270 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100271
272 return 0;
273}
274
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100275int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100276{
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000277 unsigned long flags;
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100278 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100279 return 1;
280 reg += 0x40; /* 0x40 upwards are registers. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000281 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100282 outl(reg, emu->port + A_IOCFG);
283 udelay(10);
284 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
285 udelay(10);
286 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000287 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100288
289 return 0;
290}
291
292/* Each Destination has one and only one Source,
293 * but one Source can feed any number of Destinations simultaneously.
294 */
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100295int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100296{
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) );
301
302 return 0;
303}
304
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100305void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
307 unsigned long flags;
308 unsigned int enable;
309
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);
314}
315
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100316void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
318 unsigned long flags;
319 unsigned int enable;
320
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);
325}
326
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100327void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
329 unsigned long flags;
330 unsigned int val;
331
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);
338 } else {
339 outl(CLIEL << 16, emu->port + PTR);
340 val = inl(emu->port + DATA);
341 val |= 1 << voicenum;
342 }
343 outl(val, emu->port + DATA);
344 spin_unlock_irqrestore(&emu->emu_lock, flags);
345}
346
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100347void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 unsigned long flags;
350 unsigned int val;
351
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));
358 } else {
359 outl(CLIEL << 16, emu->port + PTR);
360 val = inl(emu->port + DATA);
361 val &= ~(1 << voicenum);
362 }
363 outl(val, emu->port + DATA);
364 spin_unlock_irqrestore(&emu->emu_lock, flags);
365}
366
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100367void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 unsigned long flags;
370
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);
376 } else {
377 outl(CLIPL << 16, emu->port + PTR);
378 voicenum = 1 << voicenum;
379 }
380 outl(voicenum, emu->port + DATA);
381 spin_unlock_irqrestore(&emu->emu_lock, flags);
382}
383
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100384void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386 unsigned long flags;
387 unsigned int val;
388
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);
395 } else {
396 outl(HLIEL << 16, emu->port + PTR);
397 val = inl(emu->port + DATA);
398 val |= 1 << voicenum;
399 }
400 outl(val, emu->port + DATA);
401 spin_unlock_irqrestore(&emu->emu_lock, flags);
402}
403
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100404void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405{
406 unsigned long flags;
407 unsigned int val;
408
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));
415 } else {
416 outl(HLIEL << 16, emu->port + PTR);
417 val = inl(emu->port + DATA);
418 val &= ~(1 << voicenum);
419 }
420 outl(val, emu->port + DATA);
421 spin_unlock_irqrestore(&emu->emu_lock, flags);
422}
423
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100424void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
426 unsigned long flags;
427
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);
433 } else {
434 outl(HLIPL << 16, emu->port + PTR);
435 voicenum = 1 << voicenum;
436 }
437 outl(voicenum, emu->port + DATA);
438 spin_unlock_irqrestore(&emu->emu_lock, flags);
439}
440
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100441void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
443 unsigned long flags;
444 unsigned int sol;
445
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);
452 } else {
453 outl(SOLEL << 16, emu->port + PTR);
454 sol = inl(emu->port + DATA);
455 sol |= 1 << voicenum;
456 }
457 outl(sol, emu->port + DATA);
458 spin_unlock_irqrestore(&emu->emu_lock, flags);
459}
460
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100461void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
463 unsigned long flags;
464 unsigned int sol;
465
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));
472 } else {
473 outl(SOLEL << 16, emu->port + PTR);
474 sol = inl(emu->port + DATA);
475 sol &= ~(1 << voicenum);
476 }
477 outl(sol, emu->port + DATA);
478 spin_unlock_irqrestore(&emu->emu_lock, flags);
479}
480
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100481void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 volatile unsigned count;
484 unsigned int newtime = 0, curtime;
485
486 curtime = inl(emu->port + WC) >> 6;
487 while (wait-- > 0) {
488 count = 0;
489 while (count++ < 16384) {
490 newtime = inl(emu->port + WC) >> 6;
491 if (newtime != curtime)
492 break;
493 }
Roel Kluin5a47fa32009-04-16 23:54:04 +0200494 if (count > 16384)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 break;
496 curtime = newtime;
497 }
498}
499
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100500unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100502 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 unsigned long flags;
504 unsigned short val;
505
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);
510 return val;
511}
512
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100513void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100515 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 unsigned long flags;
517
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);
522}
523
524/*
525 * convert rate to pitch
526 */
527
528unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
529{
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
547 };
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
565 };
566 int i;
567
568 if (rate == 0)
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)]);
577 }
578 rate <<= 1;
579 }
580
581 return 0; /* Should never reach this point */
582}
583