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 <linux/time.h>
29#include <sound/core.h>
30#include <sound/emu10k1.h>
31#include <linux/delay.h>
32#include <linux/export.h>
33#include "p17v.h"
34
35unsigned 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
66EXPORT_SYMBOL(snd_emu10k1_ptr_read);
67
68void 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	if (snd_BUG_ON(!emu))
75		return;
76	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
100EXPORT_SYMBOL(snd_emu10k1_ptr_write);
101
102unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
103					  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
118void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
119				   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
134int 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;
140	int err = 0;
141
142	/* This function is not re-entrant, so protect against it. */
143	spin_lock(&emu->spi_lock);
144	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. */
149		err = 1;
150		goto spi_write_exit;
151	}
152	if (data > 0xffff) {
153		/* Only 16bit values allowed */
154		err = 1;
155		goto spi_write_exit;
156	}
157
158	tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
159	reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
160	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 */
166	for (n = 0; n < 100; n++) {
167		udelay(10);
168		tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
169		if (!(tmp & 0x10000)) {
170			result = 0;
171			break;
172		}
173	}
174	if (result) {
175		/* Timed out */
176		err = 1;
177		goto spi_write_exit;
178	}
179	snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
180	tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
181	err = 0;
182spi_write_exit:
183	spin_unlock(&emu->spi_lock);
184	return err;
185}
186
187/* 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;
196	int err = 0;
197
198	if ((reg > 0x7f) || (value > 0x1ff)) {
199		dev_err(emu->card->dev, "i2c_write: invalid values.\n");
200		return -EINVAL;
201	}
202
203	/* This function is not re-entrant, so protect against it. */
204	spin_lock(&emu->i2c_lock);
205
206	tmp = reg << 25 | value << 16;
207
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 */
214		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) {
220			mdelay(1);
221			status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
222			timeout++;
223			if ((status & I2C_A_ADC_START) == 0)
224				break;
225
226			if (timeout > 1000) {
227				dev_warn(emu->card->dev,
228					   "emu10k1:I2C:timeout status=0x%x\n",
229					   status);
230				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) {
239		dev_err(emu->card->dev, "Writing to ADC failed!\n");
240		dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
241			status, reg, value);
242		/* dump_stack(); */
243		err = -EINVAL;
244	}
245
246	spin_unlock(&emu->i2c_lock);
247	return err;
248}
249
250int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
251{
252	unsigned long flags;
253
254	if (reg > 0x3f)
255		return 1;
256	reg += 0x40; /* 0x40 upwards are registers. */
257	if (value > 0x3f) /* 0 to 0x3f are values */
258		return 1;
259	spin_lock_irqsave(&emu->emu_lock, flags);
260	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. */
267	spin_unlock_irqrestore(&emu->emu_lock, flags);
268
269	return 0;
270}
271
272int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
273{
274	unsigned long flags;
275	if (reg > 0x3f)
276		return 1;
277	reg += 0x40; /* 0x40 upwards are registers. */
278	spin_lock_irqsave(&emu->emu_lock, flags);
279	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);
284	spin_unlock_irqrestore(&emu->emu_lock, flags);
285
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 */
292int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
293{
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
302void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
303{
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
313void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
314{
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
324void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
325{
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
344void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
345{
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
364void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
365{
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
381void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
382{
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
401void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
402{
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
421void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
422{
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
438void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
439{
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
458void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
459{
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
478void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
479{
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		}
491		if (count > 16384)
492			break;
493		curtime = newtime;
494	}
495}
496
497unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
498{
499	struct snd_emu10k1 *emu = ac97->private_data;
500	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
510void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
511{
512	struct snd_emu10k1 *emu = ac97->private_data;
513	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
581