📄 cs4281m.c
字号:
printk("SOUND_PCM_READ_CHANNELS:\n")); break; case SOUND_PCM_READ_BITS: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n")); break; case SOUND_PCM_WRITE_FILTER: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_WRITE_FILTER:\n")); break; case SNDCTL_DSP_SETSYNCRO: CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n")); break; case SOUND_PCM_READ_FILTER: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n")); break; case SOUND_MIXER_PRIVATE1: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n")); break; case SOUND_MIXER_PRIVATE2: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n")); break; case SOUND_MIXER_PRIVATE3: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n")); break; case SOUND_MIXER_PRIVATE4: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n")); break; case SOUND_MIXER_PRIVATE5: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n")); break; case SOUND_MIXER_INFO: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n")); break; case SOUND_OLD_MIXER_INFO: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n")); break; default: switch (_IOC_NR(x)) { case SOUND_MIXER_VOLUME: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_VOLUME:\n")); break; case SOUND_MIXER_SPEAKER: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SPEAKER:\n")); break; case SOUND_MIXER_RECLEV: CS_DBGOUT(CS_IOCTL, 4, 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);// --------------------------------------------------------------------- //// Hardware Interfaces For the CS4281////******************************************************************************// "delayus()-- Delay for the specified # of microseconds.//******************************************************************************static void delayus(struct cs4281_state *s, u32 delay){ u32 j; if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) { 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=0; 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 < 100; 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 __devinit int 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"));#ifndef NOT_CS4281_PM if(!card) return 1;#endif temp2 = readl(card->pBA0 + BA0_CFLR); CS_DBGOUT(CS_INIT | CS_ERROR | CS_PARMS, 4, printk(KERN_INFO "cs4281: cs4281_hw_init() CFLR 0x%x\n", temp2)); if(temp2 != CS4281_CFLR_DEFAULT) { CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO "cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n", temp2,CS4281_CFLR_DEFAULT)); writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR); temp2 = readl(card->pBA0 + BA0_CFLR); if(temp2 != CS4281_CFLR_DEFAULT) { CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n")); return 1; } } //***************************************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(card,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(card,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(card,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(card,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(card,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"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -