blob: 706b4f0c6806b00495e20cbb9bdccd5bba63491f [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
Takashi Iwai4913cd62014-03-05 12:13:10 +010074 if (snd_BUG_ON(!emu))
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +000075 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
77 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
78
79 if (reg & 0xff000000) {
80 unsigned char size, offset;
81
82 size = (reg >> 24) & 0x3f;
83 offset = (reg >> 16) & 0x1f;
84 mask = ((1 << size) - 1) << offset;
85 data = (data << offset) & mask;
86
87 spin_lock_irqsave(&emu->emu_lock, flags);
88 outl(regptr, emu->port + PTR);
89 data |= inl(emu->port + DATA) & ~mask;
90 outl(data, emu->port + DATA);
91 spin_unlock_irqrestore(&emu->emu_lock, flags);
92 } else {
93 spin_lock_irqsave(&emu->emu_lock, flags);
94 outl(regptr, emu->port + PTR);
95 outl(data, emu->port + DATA);
96 spin_unlock_irqrestore(&emu->emu_lock, flags);
97 }
98}
99
Takashi Iwai2dd31de2006-04-28 15:13:39 +0200100EXPORT_SYMBOL(snd_emu10k1_ptr_write);
101
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100102unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 unsigned int reg,
104 unsigned int chn)
105{
106 unsigned long flags;
107 unsigned int regptr, val;
108
109 regptr = (reg << 16) | chn;
110
111 spin_lock_irqsave(&emu->emu_lock, flags);
112 outl(regptr, emu->port + 0x20 + PTR);
113 val = inl(emu->port + 0x20 + DATA);
114 spin_unlock_irqrestore(&emu->emu_lock, flags);
115 return val;
116}
117
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100118void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 unsigned int reg,
120 unsigned int chn,
121 unsigned int data)
122{
123 unsigned int regptr;
124 unsigned long flags;
125
126 regptr = (reg << 16) | chn;
127
128 spin_lock_irqsave(&emu->emu_lock, flags);
129 outl(regptr, emu->port + 0x20 + PTR);
130 outl(data, emu->port + 0x20 + DATA);
131 spin_unlock_irqrestore(&emu->emu_lock, flags);
132}
133
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100134int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
135 unsigned int data)
136{
137 unsigned int reset, set;
138 unsigned int reg, tmp;
139 int n, result;
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000140 int err = 0;
141
142 /* This function is not re-entrant, so protect against it. */
143 spin_lock(&emu->spi_lock);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100144 if (emu->card_capabilities->ca0108_chip)
145 reg = 0x3c; /* PTR20, reg 0x3c */
146 else {
147 /* For other chip types the SPI register
148 * is currently unknown. */
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000149 err = 1;
150 goto spi_write_exit;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100151 }
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000152 if (data > 0xffff) {
153 /* Only 16bit values allowed */
154 err = 1;
155 goto spi_write_exit;
156 }
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100157
158 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100159 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100160 set = reset | 0x10000; /* Set xxx1xxxx */
161 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
162 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
163 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
164 result = 1;
165 /* Wait for status bit to return to 0 */
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100166 for (n = 0; n < 100; n++) {
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100167 udelay(10);
168 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
169 if (!(tmp & 0x10000)) {
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100170 result = 0;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100171 break;
172 }
173 }
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000174 if (result) {
175 /* Timed out */
176 err = 1;
177 goto spi_write_exit;
178 }
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100179 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
180 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000181 err = 0;
182spi_write_exit:
183 spin_unlock(&emu->spi_lock);
184 return err;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100185}
186
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000187/* The ADC does not support i2c read, so only write is implemented */
188int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
189 u32 reg,
190 u32 value)
191{
192 u32 tmp;
193 int timeout = 0;
194 int status;
195 int retry;
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000196 int err = 0;
197
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000198 if ((reg > 0x7f) || (value > 0x1ff)) {
Takashi Iwai6f002b02014-02-25 17:02:09 +0100199 dev_err(emu->card->dev, "i2c_write: invalid values.\n");
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000200 return -EINVAL;
201 }
202
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000203 /* This function is not re-entrant, so protect against it. */
204 spin_lock(&emu->i2c_lock);
205
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000206 tmp = reg << 25 | value << 16;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000207
208 /* This controls the I2C connected to the WM8775 ADC Codec */
209 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
210 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
211
212 for (retry = 0; retry < 10; retry++) {
213 /* Send the data to i2c */
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000214 tmp = 0;
215 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
216 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
217
218 /* Wait till the transaction ends */
219 while (1) {
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000220 mdelay(1);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000221 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000222 timeout++;
223 if ((status & I2C_A_ADC_START) == 0)
224 break;
225
226 if (timeout > 1000) {
Takashi Iwai6f002b02014-02-25 17:02:09 +0100227 dev_warn(emu->card->dev,
Takashi Iwai28a97c12009-02-05 16:08:14 +0100228 "emu10k1:I2C:timeout status=0x%x\n",
229 status);
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000230 break;
231 }
232 }
233 //Read back and see if the transaction is successful
234 if ((status & I2C_A_ADC_ABORT) == 0)
235 break;
236 }
237
238 if (retry == 10) {
Takashi Iwai6f002b02014-02-25 17:02:09 +0100239 dev_err(emu->card->dev, "Writing to ADC failed!\n");
240 dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000241 status, reg, value);
242 /* dump_stack(); */
243 err = -EINVAL;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000244 }
245
James Courtier-Duttonc94fa4c2007-11-10 17:55:14 +0000246 spin_unlock(&emu->i2c_lock);
247 return err;
James Courtier-Dutton184c1e22006-12-06 15:58:02 +0000248}
249
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100250int snd_emu1010_fpga_write(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;
253
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100254 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100255 return 1;
256 reg += 0x40; /* 0x40 upwards are registers. */
Roel Kluin84ed1a12009-10-23 16:03:08 +0200257 if (value > 0x3f) /* 0 to 0x3f are values */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100258 return 1;
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000259 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100260 outl(reg, emu->port + A_IOCFG);
261 udelay(10);
262 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
263 udelay(10);
264 outl(value, emu->port + A_IOCFG);
265 udelay(10);
266 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000267 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100268
269 return 0;
270}
271
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100272int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100273{
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000274 unsigned long flags;
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100275 if (reg > 0x3f)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100276 return 1;
277 reg += 0x40; /* 0x40 upwards are registers. */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000278 spin_lock_irqsave(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100279 outl(reg, emu->port + A_IOCFG);
280 udelay(10);
281 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
282 udelay(10);
283 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
James Courtier-Dutton190d2c42007-11-04 14:08:26 +0000284 spin_unlock_irqrestore(&emu->emu_lock, flags);
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100285
286 return 0;
287}
288
289/* Each Destination has one and only one Source,
290 * but one Source can feed any number of Destinations simultaneously.
291 */
James Courtier-Duttonf93abe52007-07-26 18:31:39 +0100292int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100293{
294 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
295 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
296 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
297 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
298
299 return 0;
300}
301
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100302void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 unsigned long flags;
305 unsigned int enable;
306
307 spin_lock_irqsave(&emu->emu_lock, flags);
308 enable = inl(emu->port + INTE) | intrenb;
309 outl(enable, emu->port + INTE);
310 spin_unlock_irqrestore(&emu->emu_lock, flags);
311}
312
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100313void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
315 unsigned long flags;
316 unsigned int enable;
317
318 spin_lock_irqsave(&emu->emu_lock, flags);
319 enable = inl(emu->port + INTE) & ~intrenb;
320 outl(enable, emu->port + INTE);
321 spin_unlock_irqrestore(&emu->emu_lock, flags);
322}
323
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100324void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 unsigned long flags;
327 unsigned int val;
328
329 spin_lock_irqsave(&emu->emu_lock, flags);
330 /* voice interrupt */
331 if (voicenum >= 32) {
332 outl(CLIEH << 16, emu->port + PTR);
333 val = inl(emu->port + DATA);
334 val |= 1 << (voicenum - 32);
335 } else {
336 outl(CLIEL << 16, emu->port + PTR);
337 val = inl(emu->port + DATA);
338 val |= 1 << voicenum;
339 }
340 outl(val, emu->port + DATA);
341 spin_unlock_irqrestore(&emu->emu_lock, flags);
342}
343
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100344void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 unsigned long flags;
347 unsigned int val;
348
349 spin_lock_irqsave(&emu->emu_lock, flags);
350 /* voice interrupt */
351 if (voicenum >= 32) {
352 outl(CLIEH << 16, emu->port + PTR);
353 val = inl(emu->port + DATA);
354 val &= ~(1 << (voicenum - 32));
355 } else {
356 outl(CLIEL << 16, emu->port + PTR);
357 val = inl(emu->port + DATA);
358 val &= ~(1 << voicenum);
359 }
360 outl(val, emu->port + DATA);
361 spin_unlock_irqrestore(&emu->emu_lock, flags);
362}
363
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100364void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
366 unsigned long flags;
367
368 spin_lock_irqsave(&emu->emu_lock, flags);
369 /* voice interrupt */
370 if (voicenum >= 32) {
371 outl(CLIPH << 16, emu->port + PTR);
372 voicenum = 1 << (voicenum - 32);
373 } else {
374 outl(CLIPL << 16, emu->port + PTR);
375 voicenum = 1 << voicenum;
376 }
377 outl(voicenum, emu->port + DATA);
378 spin_unlock_irqrestore(&emu->emu_lock, flags);
379}
380
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100381void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 unsigned long flags;
384 unsigned int val;
385
386 spin_lock_irqsave(&emu->emu_lock, flags);
387 /* voice interrupt */
388 if (voicenum >= 32) {
389 outl(HLIEH << 16, emu->port + PTR);
390 val = inl(emu->port + DATA);
391 val |= 1 << (voicenum - 32);
392 } else {
393 outl(HLIEL << 16, emu->port + PTR);
394 val = inl(emu->port + DATA);
395 val |= 1 << voicenum;
396 }
397 outl(val, emu->port + DATA);
398 spin_unlock_irqrestore(&emu->emu_lock, flags);
399}
400
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100401void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
403 unsigned long flags;
404 unsigned int val;
405
406 spin_lock_irqsave(&emu->emu_lock, flags);
407 /* voice interrupt */
408 if (voicenum >= 32) {
409 outl(HLIEH << 16, emu->port + PTR);
410 val = inl(emu->port + DATA);
411 val &= ~(1 << (voicenum - 32));
412 } else {
413 outl(HLIEL << 16, emu->port + PTR);
414 val = inl(emu->port + DATA);
415 val &= ~(1 << voicenum);
416 }
417 outl(val, emu->port + DATA);
418 spin_unlock_irqrestore(&emu->emu_lock, flags);
419}
420
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100421void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
423 unsigned long flags;
424
425 spin_lock_irqsave(&emu->emu_lock, flags);
426 /* voice interrupt */
427 if (voicenum >= 32) {
428 outl(HLIPH << 16, emu->port + PTR);
429 voicenum = 1 << (voicenum - 32);
430 } else {
431 outl(HLIPL << 16, emu->port + PTR);
432 voicenum = 1 << voicenum;
433 }
434 outl(voicenum, emu->port + DATA);
435 spin_unlock_irqrestore(&emu->emu_lock, flags);
436}
437
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100438void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 unsigned long flags;
441 unsigned int sol;
442
443 spin_lock_irqsave(&emu->emu_lock, flags);
444 /* voice interrupt */
445 if (voicenum >= 32) {
446 outl(SOLEH << 16, emu->port + PTR);
447 sol = inl(emu->port + DATA);
448 sol |= 1 << (voicenum - 32);
449 } else {
450 outl(SOLEL << 16, emu->port + PTR);
451 sol = inl(emu->port + DATA);
452 sol |= 1 << voicenum;
453 }
454 outl(sol, emu->port + DATA);
455 spin_unlock_irqrestore(&emu->emu_lock, flags);
456}
457
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100458void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
460 unsigned long flags;
461 unsigned int sol;
462
463 spin_lock_irqsave(&emu->emu_lock, flags);
464 /* voice interrupt */
465 if (voicenum >= 32) {
466 outl(SOLEH << 16, emu->port + PTR);
467 sol = inl(emu->port + DATA);
468 sol &= ~(1 << (voicenum - 32));
469 } else {
470 outl(SOLEL << 16, emu->port + PTR);
471 sol = inl(emu->port + DATA);
472 sol &= ~(1 << voicenum);
473 }
474 outl(sol, emu->port + DATA);
475 spin_unlock_irqrestore(&emu->emu_lock, flags);
476}
477
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100478void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
480 volatile unsigned count;
481 unsigned int newtime = 0, curtime;
482
483 curtime = inl(emu->port + WC) >> 6;
484 while (wait-- > 0) {
485 count = 0;
486 while (count++ < 16384) {
487 newtime = inl(emu->port + WC) >> 6;
488 if (newtime != curtime)
489 break;
490 }
Roel Kluin5a47fa32009-04-16 23:54:04 +0200491 if (count > 16384)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 break;
493 curtime = newtime;
494 }
495}
496
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100497unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100499 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 unsigned long flags;
501 unsigned short val;
502
503 spin_lock_irqsave(&emu->emu_lock, flags);
504 outb(reg, emu->port + AC97ADDRESS);
505 val = inw(emu->port + AC97DATA);
506 spin_unlock_irqrestore(&emu->emu_lock, flags);
507 return val;
508}
509
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100510void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100512 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 unsigned long flags;
514
515 spin_lock_irqsave(&emu->emu_lock, flags);
516 outb(reg, emu->port + AC97ADDRESS);
517 outw(data, emu->port + AC97DATA);
518 spin_unlock_irqrestore(&emu->emu_lock, flags);
519}
520
521/*
522 * convert rate to pitch
523 */
524
525unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
526{
527 static u32 logMagTable[128] = {
528 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
529 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
530 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
531 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
532 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
533 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
534 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
535 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
536 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
537 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
538 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
539 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
540 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
541 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
542 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
543 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
544 };
545 static char logSlopeTable[128] = {
546 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
547 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
548 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
549 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
550 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
551 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
552 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
553 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
554 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
555 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
556 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
557 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
558 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
559 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
560 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
561 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
562 };
563 int i;
564
565 if (rate == 0)
566 return 0; /* Bail out if no leading "1" */
567 rate *= 11185; /* Scale 48000 to 0x20002380 */
568 for (i = 31; i > 0; i--) {
569 if (rate & 0x80000000) { /* Detect leading "1" */
570 return (((unsigned int) (i - 15) << 20) +
571 logMagTable[0x7f & (rate >> 24)] +
572 (0x7f & (rate >> 17)) *
573 logSlopeTable[0x7f & (rate >> 24)]);
574 }
575 rate <<= 1;
576 }
577
578 return 0; /* Should never reach this point */
579}
580