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