⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cs4281.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				  printk("SOUND_MIXER_RECLEV:\n"));			break;		case SOUND_MIXER_MIC:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_MIC:\n"));			break;		case SOUND_MIXER_SYNTH:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_SYNTH:\n"));			break;		case SOUND_MIXER_RECSRC:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_RECSRC:\n"));			break;		case SOUND_MIXER_DEVMASK:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_DEVMASK:\n"));			break;		case SOUND_MIXER_RECMASK:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_RECMASK:\n"));			break;		case SOUND_MIXER_STEREODEVS:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_STEREODEVS:\n"));			break;		case SOUND_MIXER_CAPS:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_CAPS:\n"));			break;		default:			i = _IOC_NR(x);			if (i >= SOUND_MIXER_NRDEVICES			    || !(vidx = mixtable1[i])) {				CS_DBGOUT(CS_IOCTL, 4,					  printk					  ("UNKNOWN IOCTL: 0x%.8x NR=%d\n",					   x, i));			} else {				CS_DBGOUT(CS_IOCTL, 4,					  printk					  ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n",					   x, i));			}			break;		}	}}#endifstatic int prog_dmabuf_adc(struct cs4281_state *s);static void prog_codec(struct cs4281_state *s, unsigned type);static struct cs4281_state *devs = NULL;// --------------------------------------------------------------------- ////              Hardware Interfaces For the CS4281////******************************************************************************// "delayus()-- Delay for the specified # of microseconds.//******************************************************************************static void delayus(u32 delay){	u32 j;	if (delay > 9999) {		j = (delay * HZ) / 1000000;	/* calculate delay in jiffies  */		if (j < 1)			j = 1;	/* minimum one jiffy. */		current->state = TASK_UNINTERRUPTIBLE;		schedule_timeout(j);	} else		udelay(delay);	return;}//******************************************************************************// "cs4281_read_ac97" -- Reads a word from the specified location in the//               CS4281's address space(based on the BA0 register).//// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register,//                                            0h for reads.// 3. Write ACCTL = Control Register = 460h for initiating the write// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h// 5. if DCV not cleared, break and return error// 6. Read ACSTS = Status Register = 464h, check VSTS bit//****************************************************************************static int cs4281_read_ac97(struct cs4281_state *card, u32 offset,			    u32 * value){	u32 count, status;	// Make sure that there is not data sitting	// around from a previous uncompleted access.	// ACSDA = Status Data Register = 47Ch	status = readl(card->pBA0 + BA0_ACSDA);	// Setup the AC97 control registers on the CS4281 to send the	// appropriate command to the AC97 to perform the read.	// ACCAD = Command Address Register = 46Ch	// ACCDA = Command Data Register = 470h	// ACCTL = Control Register = 460h	// bit DCV - will clear when process completed	// bit CRW - Read command	// bit VFRM - valid frame enabled	// bit ESYN - ASYNC generation enabled	// Get the actual AC97 register from the offset	writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);	writel(0, card->pBA0 + BA0_ACCDA);	writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN,	       card->pBA0 + BA0_ACCTL);	// Wait for the read to occur.	for (count = 0; count < 10; count++) {		// First, we want to wait for a short time.		udelay(25);		// Now, check to see if the read has completed.		// ACCTL = 460h, DCV should be reset by now and 460h = 17h		if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV))			break;	}	// Make sure the read completed.	if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)		return 1;	// Wait for the valid status bit to go active.	for (count = 0; count < 10; count++) {		// Read the AC97 status register.		// ACSTS = Status Register = 464h		status = readl(card->pBA0 + BA0_ACSTS);		// See if we have valid status.		// VSTS - Valid Status		if (status & ACSTS_VSTS)			break;		// Wait for a short while.		udelay(25);	}	// Make sure we got valid status.	if (!(status & ACSTS_VSTS))		return 1;	// Read the data returned from the AC97 register.	// ACSDA = Status Data Register = 474h	*value = readl(card->pBA0 + BA0_ACSDA);	// Success.	return (0);}//****************************************************************************//// "cs4281_write_ac97()"-- writes a word to the specified location in the// CS461x's address space (based on the part's base address zero register).//// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg.// 3. Write ACCTL = Control Register = 460h for initiating the write// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h// 5. if DCV not cleared, break and return error////****************************************************************************static int cs4281_write_ac97(struct cs4281_state *card, u32 offset,			     u32 value){	u32 count, status;	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n"));	// Setup the AC97 control registers on the CS4281 to send the	// appropriate command to the AC97 to perform the read.	// ACCAD = Command Address Register = 46Ch	// ACCDA = Command Data Register = 470h	// ACCTL = Control Register = 460h	// set DCV - will clear when process completed	// reset CRW - Write command	// set VFRM - valid frame enabled	// set ESYN - ASYNC generation enabled	// set RSTN - ARST# inactive, AC97 codec not reset	// Get the actual AC97 register from the offset	writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);	writel(value, card->pBA0 + BA0_ACCDA);	writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN,	       card->pBA0 + BA0_ACCTL);	// Wait for the write to occur.	for (count = 0; count < 10; count++) {		// First, we want to wait for a short time.		udelay(25);		// Now, check to see if the write has completed.		// ACCTL = 460h, DCV should be reset by now and 460h = 07h		status = readl(card->pBA0 + BA0_ACCTL);		if (!(status & ACCTL_DCV))			break;	}	// Make sure the write completed.	if (status & ACCTL_DCV) {		CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO					      "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n"));		return 1;	}	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n"));	// Success.	return 0;}//******************************************************************************// "Init4281()" -- Bring up the part.//******************************************************************************static int __devinit cs4281_hw_init(struct cs4281_state *card){	u32 ac97_slotid;	u32 temp1, temp2;	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n"));	//***************************************7	//  Set up the Sound System Configuration	//***************************************	// Set the 'Configuration Write Protect' register	// to 4281h.  Allows vendor-defined configuration	// space between 0e4h and 0ffh to be written.	writel(0x4281, card->pBA0 + BA0_CWPR);	// (3e0h)	// (0), Blast the clock control register to zero so that the	// PLL starts out in a known state, and blast the master serial	// port control register to zero so that the serial ports also	// start out in a known state.	writel(0, card->pBA0 + BA0_CLKCR1);	// (400h)	writel(0, card->pBA0 + BA0_SERMC);	// (420h)	// (1), Make ESYN go to zero to turn off	// the Sync pulse on the AC97 link.	writel(0, card->pBA0 + BA0_ACCTL);	udelay(50);	// (2) Drive the ARST# pin low for a minimum of 1uS (as defined in	// the AC97 spec) and then drive it high.  This is done for non	// AC97 modes since there might be logic external to the CS461x	// that uses the ARST# line for a reset.	writel(0, card->pBA0 + BA0_SPMC);	// (3ech)	udelay(100);	writel(SPMC_RSTN, card->pBA0 + BA0_SPMC);	delayus(50000);		// Wait 50 ms for ABITCLK to become stable.	// (3) Turn on the Sound System Clocks.	writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1);	// (400h)	delayus(50000);		// Wait for the PLL to stabilize.	// Turn on clocking of the core (CLKCR1(400h) = 0x00000030)	writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1);	// (4) Power on everything for now..	writel(0x7E, card->pBA0 + BA0_SSPM);	// (740h)	// (5) Wait for clock stabilization.	for (temp1 = 0; temp1 < 1000; temp1++) {		udelay(1000);		if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)			break;	}	if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) {		CS_DBGOUT(CS_ERROR, 1,			  printk(KERN_ERR "cs4281: DLLRDY failed!\n"));		return -EIO;	}	// (6) Enable ASYNC generation.	writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL);	// (460h)	// Now wait 'for a short while' to allow the  AC97	// part to start generating bit clock. (so we don't	// Try to start the PLL without an input clock.)	delayus(50000);	// Set the serial port timing configuration, so that the	// clock control circuit gets its clock from the right place.	writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC);	// (420h)=2.	// (7) Wait for the codec ready signal from the AC97 codec.	for (temp1 = 0; temp1 < 1000; temp1++) {		// Delay a mil to let things settle out and		// to prevent retrying the read too quickly.		udelay(1000);		if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)	// If ready,  (464h)			break;	//   exit the 'for' loop.	}	if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY))	// If never came ready,	{		CS_DBGOUT(CS_FUNCTION, 2,			  printk(KERN_ERR				 "cs4281: ACSTS never came ready!\n"));		return -EIO;	//   exit initialization.	}	// (8) Assert the 'valid frame' signal so we can	// begin sending commands to the AC97 codec.	writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL);	// (460h)	// (9), Wait until CODEC calibration is finished.	// Print an error message if it doesn't.	for (temp1 = 0; temp1 < 1000; temp1++) {		delayus(10000);		// Read the AC97 Powerdown Control/Status Register.		cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2);		if ((temp2 & 0x0000000F) == 0x0000000F)			break;	}	if ((temp2 & 0x0000000F) != 0x0000000F) {		CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR						 "cs4281: Codec failed to calibrate.  Status = %.8x.\n",						 temp2));		return -EIO;	}	// (10), Set the serial port timing configuration, so that the	// clock control circuit gets its clock from the right place.	writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC);	// (420h)=2.	// (11) Wait until we've sampled input slots 3 & 4 as valid, meaning	// that the codec is pumping ADC data across the AC link.	for (temp1 = 0; temp1 < 1000; temp1++) {		// Delay a mil to let things settle out and		// to prevent retrying the read too quickly.		delayus(1000);	//(test)		// Read the input slot valid register;  See		// if input slots 3 and 4 are valid yet.		if (		    (readl(card->pBA0 + BA0_ACISV) &		     (ACISV_ISV3 | ACISV_ISV4)) ==		    (ACISV_ISV3 | ACISV_ISV4)) break;	// Exit the 'for' if slots are valid.	}	// If we never got valid data, exit initialization.	if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4))	    != (ACISV_ISV3 | ACISV_ISV4)) {		CS_DBGOUT(CS_FUNCTION, 2,			  printk(KERN_ERR				 "cs4281: Never got valid data!\n"));		return -EIO;	// If no valid data, exit initialization.	}	// (12), Start digital data transfer of audio data to the codec.	writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV);	// (468h)	//**************************************	// Unmute the Master and Alternate	// (headphone) volumes.  Set to max.	//**************************************	cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0);	cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0);	//******************************************	// Power on the DAC(AddDACUser()from main())	//******************************************	cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);	cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff);	// Wait until we sample a DAC ready state.	for (temp2 = 0; temp2 < 32; temp2++) {		// Let's wait a mil to let things settle.		delayus(1000);		// Read the current state of the power control reg.		cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);		// If the DAC ready state bit is set, stop waiting.		if (temp1 & 0x2)			break;	}	//******************************************	// Power on the ADC(AddADCUser()from main())	//******************************************	cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);	cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff);	// Wait until we sample ADC ready state.	for (temp2 = 0; temp2 < 32; temp2++) {		// Let's wait a mil to let things settle.		delayus(1000);		// Read the current state of the power control reg.		cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);		// If the ADC ready state bit is set, stop waiting.		if (temp1 & 0x1)			break;	}	// Set up 4281 Register contents that	// don't change for boot duration.	// For playback, we map AC97 slot 3 and 4(Left	// & Right PCM playback) to DMA Channel 0.	// Set the fifo to be 15 bytes at offset zero.	ac97_slotid = 0x01000f00;	// FCR0.RS[4:0]=1(=>slot4, right PCM playback).	// FCR0.LS[4:0]=0(=>slot3, left PCM playback).	// FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.	writel(ac97_slotid, card->pBA0 + BA0_FCR0);	// (180h)	writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0);	// Turn on FIFO Enable.	// For capture, we map AC97 slot 10 and 11(Left	// and Right PCM Record) to DMA Channel 1.	// Set the fifo to be 15 bytes at offset sixteen.	ac97_slotid = 0x0B0A0f10;	// FCR1.RS[4:0]=11(=>slot11, right PCM record).	// FCR1.LS[4:0]=10(=>slot10, left PCM record).	// FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.	writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1);	// (184h)	writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1);	// Turn on FIFO Enable.	// Map the Playback SRC to the same AC97 slots(3 & 4--	// --Playback left & right)as DMA channel 0.	// Map the record SRC to the same AC97 slots(10 & 11--	// -- Record left & right) as DMA channel 1.	ac97_slotid = 0x0b0a0100;	// SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback).	// SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).	// SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)	// SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -