PageRenderTime 76ms CodeModel.GetById 11ms app.highlight 55ms RepoModel.GetById 2ms app.codeStats 1ms

/sound/pci/emu10k1/io.c

https://bitbucket.org/abioy/linux
C | 582 lines | 458 code | 71 blank | 53 comment | 50 complexity | 02e1b8385bfa539c7156014449a5aef9 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, GPL-2.0, LGPL-2.0, AGPL-1.0
  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
 34unsigned 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
 65EXPORT_SYMBOL(snd_emu10k1_ptr_read);
 66
 67void 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
102EXPORT_SYMBOL(snd_emu10k1_ptr_write);
103
104unsigned 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
120void 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
136int 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;
184spi_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 */
190int 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(KERN_WARNING
230					   "emu10k1:I2C:timeout status=0x%x\n",
231					   status);
232				break;
233			}
234		}
235		//Read back and see if the transaction is successful
236		if ((status & I2C_A_ADC_ABORT) == 0)
237			break;
238	}
239
240	if (retry == 10) {
241		snd_printk(KERN_ERR "Writing to ADC failed!\n");
242		snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
243			status, reg, value);
244		/* dump_stack(); */
245		err = -EINVAL;
246	}
247    
248	spin_unlock(&emu->i2c_lock);
249	return err;
250}
251
252int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
253{
254	unsigned long flags;
255
256	if (reg > 0x3f)
257		return 1;
258	reg += 0x40; /* 0x40 upwards are registers. */
259	if (value > 0x3f) /* 0 to 0x3f are values */
260		return 1;
261	spin_lock_irqsave(&emu->emu_lock, flags);
262	outl(reg, emu->port + A_IOCFG);
263	udelay(10);
264	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
265	udelay(10);
266	outl(value, emu->port + A_IOCFG);
267	udelay(10);
268	outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
269	spin_unlock_irqrestore(&emu->emu_lock, flags);
270
271	return 0;
272}
273
274int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
275{
276	unsigned long flags;
277	if (reg > 0x3f)
278		return 1;
279	reg += 0x40; /* 0x40 upwards are registers. */
280	spin_lock_irqsave(&emu->emu_lock, flags);
281	outl(reg, emu->port + A_IOCFG);
282	udelay(10);
283	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
284	udelay(10);
285	*value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
286	spin_unlock_irqrestore(&emu->emu_lock, flags);
287
288	return 0;
289}
290
291/* Each Destination has one and only one Source,
292 * but one Source can feed any number of Destinations simultaneously.
293 */
294int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
295{
296	snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
297	snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
298	snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
299	snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
300
301	return 0;
302}
303
304void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
305{
306	unsigned long flags;
307	unsigned int enable;
308
309	spin_lock_irqsave(&emu->emu_lock, flags);
310	enable = inl(emu->port + INTE) | intrenb;
311	outl(enable, emu->port + INTE);
312	spin_unlock_irqrestore(&emu->emu_lock, flags);
313}
314
315void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
316{
317	unsigned long flags;
318	unsigned int enable;
319
320	spin_lock_irqsave(&emu->emu_lock, flags);
321	enable = inl(emu->port + INTE) & ~intrenb;
322	outl(enable, emu->port + INTE);
323	spin_unlock_irqrestore(&emu->emu_lock, flags);
324}
325
326void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
327{
328	unsigned long flags;
329	unsigned int val;
330
331	spin_lock_irqsave(&emu->emu_lock, flags);
332	/* voice interrupt */
333	if (voicenum >= 32) {
334		outl(CLIEH << 16, emu->port + PTR);
335		val = inl(emu->port + DATA);
336		val |= 1 << (voicenum - 32);
337	} else {
338		outl(CLIEL << 16, emu->port + PTR);
339		val = inl(emu->port + DATA);
340		val |= 1 << voicenum;
341	}
342	outl(val, emu->port + DATA);
343	spin_unlock_irqrestore(&emu->emu_lock, flags);
344}
345
346void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
347{
348	unsigned long flags;
349	unsigned int val;
350
351	spin_lock_irqsave(&emu->emu_lock, flags);
352	/* voice interrupt */
353	if (voicenum >= 32) {
354		outl(CLIEH << 16, emu->port + PTR);
355		val = inl(emu->port + DATA);
356		val &= ~(1 << (voicenum - 32));
357	} else {
358		outl(CLIEL << 16, emu->port + PTR);
359		val = inl(emu->port + DATA);
360		val &= ~(1 << voicenum);
361	}
362	outl(val, emu->port + DATA);
363	spin_unlock_irqrestore(&emu->emu_lock, flags);
364}
365
366void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
367{
368	unsigned long flags;
369
370	spin_lock_irqsave(&emu->emu_lock, flags);
371	/* voice interrupt */
372	if (voicenum >= 32) {
373		outl(CLIPH << 16, emu->port + PTR);
374		voicenum = 1 << (voicenum - 32);
375	} else {
376		outl(CLIPL << 16, emu->port + PTR);
377		voicenum = 1 << voicenum;
378	}
379	outl(voicenum, emu->port + DATA);
380	spin_unlock_irqrestore(&emu->emu_lock, flags);
381}
382
383void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
384{
385	unsigned long flags;
386	unsigned int val;
387
388	spin_lock_irqsave(&emu->emu_lock, flags);
389	/* voice interrupt */
390	if (voicenum >= 32) {
391		outl(HLIEH << 16, emu->port + PTR);
392		val = inl(emu->port + DATA);
393		val |= 1 << (voicenum - 32);
394	} else {
395		outl(HLIEL << 16, emu->port + PTR);
396		val = inl(emu->port + DATA);
397		val |= 1 << voicenum;
398	}
399	outl(val, emu->port + DATA);
400	spin_unlock_irqrestore(&emu->emu_lock, flags);
401}
402
403void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
404{
405	unsigned long flags;
406	unsigned int val;
407
408	spin_lock_irqsave(&emu->emu_lock, flags);
409	/* voice interrupt */
410	if (voicenum >= 32) {
411		outl(HLIEH << 16, emu->port + PTR);
412		val = inl(emu->port + DATA);
413		val &= ~(1 << (voicenum - 32));
414	} else {
415		outl(HLIEL << 16, emu->port + PTR);
416		val = inl(emu->port + DATA);
417		val &= ~(1 << voicenum);
418	}
419	outl(val, emu->port + DATA);
420	spin_unlock_irqrestore(&emu->emu_lock, flags);
421}
422
423void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
424{
425	unsigned long flags;
426
427	spin_lock_irqsave(&emu->emu_lock, flags);
428	/* voice interrupt */
429	if (voicenum >= 32) {
430		outl(HLIPH << 16, emu->port + PTR);
431		voicenum = 1 << (voicenum - 32);
432	} else {
433		outl(HLIPL << 16, emu->port + PTR);
434		voicenum = 1 << voicenum;
435	}
436	outl(voicenum, emu->port + DATA);
437	spin_unlock_irqrestore(&emu->emu_lock, flags);
438}
439
440void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
441{
442	unsigned long flags;
443	unsigned int sol;
444
445	spin_lock_irqsave(&emu->emu_lock, flags);
446	/* voice interrupt */
447	if (voicenum >= 32) {
448		outl(SOLEH << 16, emu->port + PTR);
449		sol = inl(emu->port + DATA);
450		sol |= 1 << (voicenum - 32);
451	} else {
452		outl(SOLEL << 16, emu->port + PTR);
453		sol = inl(emu->port + DATA);
454		sol |= 1 << voicenum;
455	}
456	outl(sol, emu->port + DATA);
457	spin_unlock_irqrestore(&emu->emu_lock, flags);
458}
459
460void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
461{
462	unsigned long flags;
463	unsigned int sol;
464
465	spin_lock_irqsave(&emu->emu_lock, flags);
466	/* voice interrupt */
467	if (voicenum >= 32) {
468		outl(SOLEH << 16, emu->port + PTR);
469		sol = inl(emu->port + DATA);
470		sol &= ~(1 << (voicenum - 32));
471	} else {
472		outl(SOLEL << 16, emu->port + PTR);
473		sol = inl(emu->port + DATA);
474		sol &= ~(1 << voicenum);
475	}
476	outl(sol, emu->port + DATA);
477	spin_unlock_irqrestore(&emu->emu_lock, flags);
478}
479
480void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
481{
482	volatile unsigned count;
483	unsigned int newtime = 0, curtime;
484
485	curtime = inl(emu->port + WC) >> 6;
486	while (wait-- > 0) {
487		count = 0;
488		while (count++ < 16384) {
489			newtime = inl(emu->port + WC) >> 6;
490			if (newtime != curtime)
491				break;
492		}
493		if (count > 16384)
494			break;
495		curtime = newtime;
496	}
497}
498
499unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
500{
501	struct snd_emu10k1 *emu = ac97->private_data;
502	unsigned long flags;
503	unsigned short val;
504
505	spin_lock_irqsave(&emu->emu_lock, flags);
506	outb(reg, emu->port + AC97ADDRESS);
507	val = inw(emu->port + AC97DATA);
508	spin_unlock_irqrestore(&emu->emu_lock, flags);
509	return val;
510}
511
512void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
513{
514	struct snd_emu10k1 *emu = ac97->private_data;
515	unsigned long flags;
516
517	spin_lock_irqsave(&emu->emu_lock, flags);
518	outb(reg, emu->port + AC97ADDRESS);
519	outw(data, emu->port + AC97DATA);
520	spin_unlock_irqrestore(&emu->emu_lock, flags);
521}
522
523/*
524 *  convert rate to pitch
525 */
526
527unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
528{
529	static u32 logMagTable[128] = {
530		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
531		0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
532		0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
533		0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
534		0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
535		0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
536		0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
537		0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
538		0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
539		0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
540		0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
541		0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
542		0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
543		0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
544		0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
545		0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
546	};
547	static char logSlopeTable[128] = {
548		0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
549		0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
550		0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
551		0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
552		0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
553		0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
554		0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
555		0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
556		0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
557		0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
558		0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
559		0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
560		0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
561		0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
562		0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
563		0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
564	};
565	int i;
566
567	if (rate == 0)
568		return 0;	/* Bail out if no leading "1" */
569	rate *= 11185;		/* Scale 48000 to 0x20002380 */
570	for (i = 31; i > 0; i--) {
571		if (rate & 0x80000000) {	/* Detect leading "1" */
572			return (((unsigned int) (i - 15) << 20) +
573			       logMagTable[0x7f & (rate >> 24)] +
574					(0x7f & (rate >> 17)) *
575					logSlopeTable[0x7f & (rate >> 24)]);
576		}
577		rate <<= 1;
578	}
579
580	return 0;		/* Should never reach this point */
581}
582