xref: /openbmc/linux/sound/pci/emu10k1/io.c (revision df388556)
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 "p17v.h"
33 
34 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
35 {
36 	unsigned long flags;
37 	unsigned int regptr, val;
38 	unsigned int mask;
39 
40 	mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
41 	regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
42 
43 	if (reg & 0xff000000) {
44 		unsigned char size, offset;
45 
46 		size = (reg >> 24) & 0x3f;
47 		offset = (reg >> 16) & 0x1f;
48 		mask = ((1 << size) - 1) << offset;
49 
50 		spin_lock_irqsave(&emu->emu_lock, flags);
51 		outl(regptr, emu->port + PTR);
52 		val = inl(emu->port + DATA);
53 		spin_unlock_irqrestore(&emu->emu_lock, flags);
54 
55 		return (val & mask) >> offset;
56 	} else {
57 		spin_lock_irqsave(&emu->emu_lock, flags);
58 		outl(regptr, emu->port + PTR);
59 		val = inl(emu->port + DATA);
60 		spin_unlock_irqrestore(&emu->emu_lock, flags);
61 		return val;
62 	}
63 }
64 
65 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
66 
67 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
68 {
69 	unsigned int regptr;
70 	unsigned long flags;
71 	unsigned int mask;
72 
73 	if (!emu) {
74 		snd_printk(KERN_ERR "ptr_write: emu is null!\n");
75 		dump_stack();
76 		return;
77 	}
78 	mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
79 	regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
80 
81 	if (reg & 0xff000000) {
82 		unsigned char size, offset;
83 
84 		size = (reg >> 24) & 0x3f;
85 		offset = (reg >> 16) & 0x1f;
86 		mask = ((1 << size) - 1) << offset;
87 		data = (data << offset) & mask;
88 
89 		spin_lock_irqsave(&emu->emu_lock, flags);
90 		outl(regptr, emu->port + PTR);
91 		data |= inl(emu->port + DATA) & ~mask;
92 		outl(data, emu->port + DATA);
93 		spin_unlock_irqrestore(&emu->emu_lock, flags);
94 	} else {
95 		spin_lock_irqsave(&emu->emu_lock, flags);
96 		outl(regptr, emu->port + PTR);
97 		outl(data, emu->port + DATA);
98 		spin_unlock_irqrestore(&emu->emu_lock, flags);
99 	}
100 }
101 
102 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
103 
104 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
105 					  unsigned int reg,
106 					  unsigned int chn)
107 {
108 	unsigned long flags;
109 	unsigned int regptr, val;
110 
111 	regptr = (reg << 16) | chn;
112 
113 	spin_lock_irqsave(&emu->emu_lock, flags);
114 	outl(regptr, emu->port + 0x20 + PTR);
115 	val = inl(emu->port + 0x20 + DATA);
116 	spin_unlock_irqrestore(&emu->emu_lock, flags);
117 	return val;
118 }
119 
120 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
121 				   unsigned int reg,
122 				   unsigned int chn,
123 				   unsigned int data)
124 {
125 	unsigned int regptr;
126 	unsigned long flags;
127 
128 	regptr = (reg << 16) | chn;
129 
130 	spin_lock_irqsave(&emu->emu_lock, flags);
131 	outl(regptr, emu->port + 0x20 + PTR);
132 	outl(data, emu->port + 0x20 + DATA);
133 	spin_unlock_irqrestore(&emu->emu_lock, flags);
134 }
135 
136 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
137 				   unsigned int data)
138 {
139 	unsigned int reset, set;
140 	unsigned int reg, tmp;
141 	int n, result;
142 	int err = 0;
143 
144 	/* This function is not re-entrant, so protect against it. */
145 	spin_lock(&emu->spi_lock);
146 	if (emu->card_capabilities->ca0108_chip)
147 		reg = 0x3c; /* PTR20, reg 0x3c */
148 	else {
149 		/* For other chip types the SPI register
150 		 * is currently unknown. */
151 		err = 1;
152 		goto spi_write_exit;
153 	}
154 	if (data > 0xffff) {
155 		/* Only 16bit values allowed */
156 		err = 1;
157 		goto spi_write_exit;
158 	}
159 
160 	tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
161 	reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
162 	set = reset | 0x10000; /* Set xxx1xxxx */
163 	snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
164 	tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
165 	snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
166 	result = 1;
167 	/* Wait for status bit to return to 0 */
168 	for (n = 0; n < 100; n++) {
169 		udelay(10);
170 		tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
171 		if (!(tmp & 0x10000)) {
172 			result = 0;
173 			break;
174 		}
175 	}
176 	if (result) {
177 		/* Timed out */
178 		err = 1;
179 		goto spi_write_exit;
180 	}
181 	snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
182 	tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
183 	err = 0;
184 spi_write_exit:
185 	spin_unlock(&emu->spi_lock);
186 	return err;
187 }
188 
189 /* The ADC does not support i2c read, so only write is implemented */
190 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
191 				u32 reg,
192 				u32 value)
193 {
194 	u32 tmp;
195 	int timeout = 0;
196 	int status;
197 	int retry;
198 	int err = 0;
199 
200 	if ((reg > 0x7f) || (value > 0x1ff)) {
201 		snd_printk(KERN_ERR "i2c_write: invalid values.\n");
202 		return -EINVAL;
203 	}
204 
205 	/* This function is not re-entrant, so protect against it. */
206 	spin_lock(&emu->i2c_lock);
207 
208 	tmp = reg << 25 | value << 16;
209 
210 	/* This controls the I2C connected to the WM8775 ADC Codec */
211 	snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
212 	tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
213 
214 	for (retry = 0; retry < 10; retry++) {
215 		/* Send the data to i2c */
216 		tmp = 0;
217 		tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
218 		snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
219 
220 		/* Wait till the transaction ends */
221 		while (1) {
222 			mdelay(1);
223 			status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
224 			timeout++;
225 			if ((status & I2C_A_ADC_START) == 0)
226 				break;
227 
228 			if (timeout > 1000) {
229                 		snd_printk("emu10k1:I2C:timeout status=0x%x\n", 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 		snd_printk(KERN_ERR "Writing to ADC failed!\n");
240 		snd_printk(KERN_ERR "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 
250 int 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 < 0 || 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 
272 int 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  */
292 int 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 
302 void 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 
313 void 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 
324 void 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 
344 void 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 
364 void 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 
381 void 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 
401 void 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 
421 void 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 
438 void 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 
458 void 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 
478 void 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 
497 unsigned 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 
510 void 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 
525 unsigned 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