xref: /openbmc/linux/sound/pci/emu10k1/io.c (revision 64c70b1c)
1 /*
2  *  Copyright (c) by Jaroslav Kysela <perex@suse.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, int reg, int value)
230 {
231 	if (reg < 0 || 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, int reg, int *value)
248 {
249 	if (reg < 0 || 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, int dst, int 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 
553