[ALSA] Changed Jaroslav Kysela's e-mail from perex@suse.cz to perex@perex.cz
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / sound / pci / emu10k1 / io.c
1 /*
2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3 * 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
28 #include <sound/driver.h>
29 #include <linux/time.h>
30 #include <sound/core.h>
31 #include <sound/emu10k1.h>
32 #include <linux/delay.h>
33 #include "p17v.h"
34
35 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
36 {
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
66 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
67
68 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
69 {
70 unsigned int regptr;
71 unsigned long flags;
72 unsigned int mask;
73
74 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
75 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
76
77 if (reg & 0xff000000) {
78 unsigned char size, offset;
79
80 size = (reg >> 24) & 0x3f;
81 offset = (reg >> 16) & 0x1f;
82 mask = ((1 << size) - 1) << offset;
83 data = (data << offset) & mask;
84
85 spin_lock_irqsave(&emu->emu_lock, flags);
86 outl(regptr, emu->port + PTR);
87 data |= inl(emu->port + DATA) & ~mask;
88 outl(data, emu->port + DATA);
89 spin_unlock_irqrestore(&emu->emu_lock, flags);
90 } else {
91 spin_lock_irqsave(&emu->emu_lock, flags);
92 outl(regptr, emu->port + PTR);
93 outl(data, emu->port + DATA);
94 spin_unlock_irqrestore(&emu->emu_lock, flags);
95 }
96 }
97
98 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
99
100 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
101 unsigned int reg,
102 unsigned int chn)
103 {
104 unsigned long flags;
105 unsigned int regptr, val;
106
107 regptr = (reg << 16) | chn;
108
109 spin_lock_irqsave(&emu->emu_lock, flags);
110 outl(regptr, emu->port + 0x20 + PTR);
111 val = inl(emu->port + 0x20 + DATA);
112 spin_unlock_irqrestore(&emu->emu_lock, flags);
113 return val;
114 }
115
116 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
117 unsigned int reg,
118 unsigned int chn,
119 unsigned int data)
120 {
121 unsigned int regptr;
122 unsigned long flags;
123
124 regptr = (reg << 16) | chn;
125
126 spin_lock_irqsave(&emu->emu_lock, flags);
127 outl(regptr, emu->port + 0x20 + PTR);
128 outl(data, emu->port + 0x20 + DATA);
129 spin_unlock_irqrestore(&emu->emu_lock, flags);
130 }
131
132 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
133 unsigned int data)
134 {
135 unsigned int reset, set;
136 unsigned int reg, tmp;
137 int n, result;
138 if (emu->card_capabilities->ca0108_chip)
139 reg = 0x3c; /* PTR20, reg 0x3c */
140 else {
141 /* For other chip types the SPI register
142 * is currently unknown. */
143 return 1;
144 }
145 if (data > 0xffff) /* Only 16bit values allowed */
146 return 1;
147
148 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
149 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
150 set = reset | 0x10000; /* Set xxx1xxxx */
151 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
152 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
153 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
154 result = 1;
155 /* Wait for status bit to return to 0 */
156 for (n = 0; n < 100; n++) {
157 udelay(10);
158 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
159 if (!(tmp & 0x10000)) {
160 result = 0;
161 break;
162 }
163 }
164 if (result) /* Timed out */
165 return 1;
166 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
167 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
168 return 0;
169 }
170
171 /* The ADC does not support i2c read, so only write is implemented */
172 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
173 u32 reg,
174 u32 value)
175 {
176 u32 tmp;
177 int timeout = 0;
178 int status;
179 int retry;
180 if ((reg > 0x7f) || (value > 0x1ff)) {
181 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
182 return -EINVAL;
183 }
184
185 tmp = reg << 25 | value << 16;
186 // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
187 /* Not sure what this I2C channel controls. */
188 /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
189
190 /* This controls the I2C connected to the WM8775 ADC Codec */
191 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
192 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
193
194 for (retry = 0; retry < 10; retry++) {
195 /* Send the data to i2c */
196 //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
197 //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
198 tmp = 0;
199 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
200 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
201
202 /* Wait till the transaction ends */
203 while (1) {
204 udelay(10);
205 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
206 // snd_printk("I2C:status=0x%x\n", status);
207 timeout++;
208 if ((status & I2C_A_ADC_START) == 0)
209 break;
210
211 if (timeout > 1000) {
212 snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
213 break;
214 }
215 }
216 //Read back and see if the transaction is successful
217 if ((status & I2C_A_ADC_ABORT) == 0)
218 break;
219 }
220
221 if (retry == 10) {
222 snd_printk(KERN_ERR "Writing to ADC failed!\n");
223 return -EINVAL;
224 }
225
226 return 0;
227 }
228
229 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
230 {
231 if (reg > 0x3f)
232 return 1;
233 reg += 0x40; /* 0x40 upwards are registers. */
234 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
235 return 1;
236 outl(reg, emu->port + A_IOCFG);
237 udelay(10);
238 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
239 udelay(10);
240 outl(value, emu->port + A_IOCFG);
241 udelay(10);
242 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
243
244 return 0;
245 }
246
247 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
248 {
249 if (reg > 0x3f)
250 return 1;
251 reg += 0x40; /* 0x40 upwards are registers. */
252 outl(reg, emu->port + A_IOCFG);
253 udelay(10);
254 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
255 udelay(10);
256 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
257
258 return 0;
259 }
260
261 /* Each Destination has one and only one Source,
262 * but one Source can feed any number of Destinations simultaneously.
263 */
264 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
265 {
266 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
267 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
268 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
269 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
270
271 return 0;
272 }
273
274 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
275 {
276 unsigned long flags;
277 unsigned int enable;
278
279 spin_lock_irqsave(&emu->emu_lock, flags);
280 enable = inl(emu->port + INTE) | intrenb;
281 outl(enable, emu->port + INTE);
282 spin_unlock_irqrestore(&emu->emu_lock, flags);
283 }
284
285 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
286 {
287 unsigned long flags;
288 unsigned int enable;
289
290 spin_lock_irqsave(&emu->emu_lock, flags);
291 enable = inl(emu->port + INTE) & ~intrenb;
292 outl(enable, emu->port + INTE);
293 spin_unlock_irqrestore(&emu->emu_lock, flags);
294 }
295
296 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
297 {
298 unsigned long flags;
299 unsigned int val;
300
301 spin_lock_irqsave(&emu->emu_lock, flags);
302 /* voice interrupt */
303 if (voicenum >= 32) {
304 outl(CLIEH << 16, emu->port + PTR);
305 val = inl(emu->port + DATA);
306 val |= 1 << (voicenum - 32);
307 } else {
308 outl(CLIEL << 16, emu->port + PTR);
309 val = inl(emu->port + DATA);
310 val |= 1 << voicenum;
311 }
312 outl(val, emu->port + DATA);
313 spin_unlock_irqrestore(&emu->emu_lock, flags);
314 }
315
316 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
317 {
318 unsigned long flags;
319 unsigned int val;
320
321 spin_lock_irqsave(&emu->emu_lock, flags);
322 /* voice interrupt */
323 if (voicenum >= 32) {
324 outl(CLIEH << 16, emu->port + PTR);
325 val = inl(emu->port + DATA);
326 val &= ~(1 << (voicenum - 32));
327 } else {
328 outl(CLIEL << 16, emu->port + PTR);
329 val = inl(emu->port + DATA);
330 val &= ~(1 << voicenum);
331 }
332 outl(val, emu->port + DATA);
333 spin_unlock_irqrestore(&emu->emu_lock, flags);
334 }
335
336 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
337 {
338 unsigned long flags;
339
340 spin_lock_irqsave(&emu->emu_lock, flags);
341 /* voice interrupt */
342 if (voicenum >= 32) {
343 outl(CLIPH << 16, emu->port + PTR);
344 voicenum = 1 << (voicenum - 32);
345 } else {
346 outl(CLIPL << 16, emu->port + PTR);
347 voicenum = 1 << voicenum;
348 }
349 outl(voicenum, emu->port + DATA);
350 spin_unlock_irqrestore(&emu->emu_lock, flags);
351 }
352
353 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
354 {
355 unsigned long flags;
356 unsigned int val;
357
358 spin_lock_irqsave(&emu->emu_lock, flags);
359 /* voice interrupt */
360 if (voicenum >= 32) {
361 outl(HLIEH << 16, emu->port + PTR);
362 val = inl(emu->port + DATA);
363 val |= 1 << (voicenum - 32);
364 } else {
365 outl(HLIEL << 16, emu->port + PTR);
366 val = inl(emu->port + DATA);
367 val |= 1 << voicenum;
368 }
369 outl(val, emu->port + DATA);
370 spin_unlock_irqrestore(&emu->emu_lock, flags);
371 }
372
373 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
374 {
375 unsigned long flags;
376 unsigned int val;
377
378 spin_lock_irqsave(&emu->emu_lock, flags);
379 /* voice interrupt */
380 if (voicenum >= 32) {
381 outl(HLIEH << 16, emu->port + PTR);
382 val = inl(emu->port + DATA);
383 val &= ~(1 << (voicenum - 32));
384 } else {
385 outl(HLIEL << 16, emu->port + PTR);
386 val = inl(emu->port + DATA);
387 val &= ~(1 << voicenum);
388 }
389 outl(val, emu->port + DATA);
390 spin_unlock_irqrestore(&emu->emu_lock, flags);
391 }
392
393 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
394 {
395 unsigned long flags;
396
397 spin_lock_irqsave(&emu->emu_lock, flags);
398 /* voice interrupt */
399 if (voicenum >= 32) {
400 outl(HLIPH << 16, emu->port + PTR);
401 voicenum = 1 << (voicenum - 32);
402 } else {
403 outl(HLIPL << 16, emu->port + PTR);
404 voicenum = 1 << voicenum;
405 }
406 outl(voicenum, emu->port + DATA);
407 spin_unlock_irqrestore(&emu->emu_lock, flags);
408 }
409
410 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
411 {
412 unsigned long flags;
413 unsigned int sol;
414
415 spin_lock_irqsave(&emu->emu_lock, flags);
416 /* voice interrupt */
417 if (voicenum >= 32) {
418 outl(SOLEH << 16, emu->port + PTR);
419 sol = inl(emu->port + DATA);
420 sol |= 1 << (voicenum - 32);
421 } else {
422 outl(SOLEL << 16, emu->port + PTR);
423 sol = inl(emu->port + DATA);
424 sol |= 1 << voicenum;
425 }
426 outl(sol, emu->port + DATA);
427 spin_unlock_irqrestore(&emu->emu_lock, flags);
428 }
429
430 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
431 {
432 unsigned long flags;
433 unsigned int sol;
434
435 spin_lock_irqsave(&emu->emu_lock, flags);
436 /* voice interrupt */
437 if (voicenum >= 32) {
438 outl(SOLEH << 16, emu->port + PTR);
439 sol = inl(emu->port + DATA);
440 sol &= ~(1 << (voicenum - 32));
441 } else {
442 outl(SOLEL << 16, emu->port + PTR);
443 sol = inl(emu->port + DATA);
444 sol &= ~(1 << voicenum);
445 }
446 outl(sol, emu->port + DATA);
447 spin_unlock_irqrestore(&emu->emu_lock, flags);
448 }
449
450 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
451 {
452 volatile unsigned count;
453 unsigned int newtime = 0, curtime;
454
455 curtime = inl(emu->port + WC) >> 6;
456 while (wait-- > 0) {
457 count = 0;
458 while (count++ < 16384) {
459 newtime = inl(emu->port + WC) >> 6;
460 if (newtime != curtime)
461 break;
462 }
463 if (count >= 16384)
464 break;
465 curtime = newtime;
466 }
467 }
468
469 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
470 {
471 struct snd_emu10k1 *emu = ac97->private_data;
472 unsigned long flags;
473 unsigned short val;
474
475 spin_lock_irqsave(&emu->emu_lock, flags);
476 outb(reg, emu->port + AC97ADDRESS);
477 val = inw(emu->port + AC97DATA);
478 spin_unlock_irqrestore(&emu->emu_lock, flags);
479 return val;
480 }
481
482 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
483 {
484 struct snd_emu10k1 *emu = ac97->private_data;
485 unsigned long flags;
486
487 spin_lock_irqsave(&emu->emu_lock, flags);
488 outb(reg, emu->port + AC97ADDRESS);
489 outw(data, emu->port + AC97DATA);
490 spin_unlock_irqrestore(&emu->emu_lock, flags);
491 }
492
493 /*
494 * convert rate to pitch
495 */
496
497 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
498 {
499 static u32 logMagTable[128] = {
500 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
501 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
502 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
503 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
504 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
505 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
506 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
507 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
508 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
509 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
510 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
511 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
512 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
513 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
514 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
515 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
516 };
517 static char logSlopeTable[128] = {
518 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
519 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
520 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
521 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
522 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
523 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
524 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
525 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
526 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
527 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
528 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
529 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
530 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
531 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
532 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
533 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
534 };
535 int i;
536
537 if (rate == 0)
538 return 0; /* Bail out if no leading "1" */
539 rate *= 11185; /* Scale 48000 to 0x20002380 */
540 for (i = 31; i > 0; i--) {
541 if (rate & 0x80000000) { /* Detect leading "1" */
542 return (((unsigned int) (i - 15) << 20) +
543 logMagTable[0x7f & (rate >> 24)] +
544 (0x7f & (rate >> 17)) *
545 logSlopeTable[0x7f & (rate >> 24)]);
546 }
547 rate <<= 1;
548 }
549
550 return 0; /* Should never reach this point */
551 }
552