📄 ac97.c
字号:
/*======================================================================
Project Name : S3C2443
Copyright 2006 by Samsung Electronics, Inc.
All rights reserved.
Project Description :
This software is only for verifying functions of the S3C2443.
Anybody can use this code without our permission.
File Name : AC97.c
Description : S3C2443 AC97 module code
Author : Junon Jeon
Dept : AP
Created Date : 2006.06.02
Version : 0.0
History
R0.0 (2006.06.02): Junon draft
- This code is derived from S3C2460A AC97 test code.
- This S3C2443 AC97 test code works with WM9710 AC97 CODEC on the SMDK2443.
- AC97 PCM-In in DMA or interrupt mode is supported.
- AC97 PCM-Out in DMA or interrupt mode is supported.
- Volume up/down is available, when codec plays PCM data.
- AC97 power down mode test is supported.
- AC97 reset timing check is supported.
- Variable ADC/DAC operation is supported.
=======================================================================*/
#include "system.h"
#include "ac97.h"
#define AC97_REC_LEN 0xfffff*4 //Max value of DMA Transfer Counter (20bit) = 0xfffff, Date Size=Word (4bytes)
//#define AC97_REC_LEN 0xfffff
#define DOWN_BUF _NONCACHE_STARTADDRESS
#define PCM_OUT_TRIGGER 8
#define PCM_IN_TRIGGER 8
#define AC97_PCM_OUT_THRESHOLD (1<<18)
#define AC97_PCM_IN_THRESHOLD (1<<17)
#define AC97_MIC_IN_THRESHOLD (1<<16)
// Global variables
unsigned int save_AC97_rGPECON, save_AC97_rGPEDAT, save_AC97_rGPEUDP;
unsigned int AC97_size, AC97_fs;
unsigned int Output_Volume,Input_Volume;
unsigned int *Rec_AC97_BUF, *Play_AC97_BUF, *End_AC97_BUF;
volatile static int timer_exit=0;
volatile short AC97_Out_INT_Exit = 0;
volatile short AC97_In_INT_Exit =0;
unsigned char *AC97_BUF,*AC97_temp;
unsigned char Volume_Control;
char AC97_Rec_Done = 0;
char Codec_Ready_Irq;
char AC97_mute = 1;
char Codec_Ready = 1;
// Functions
// GPIO port setting
void AC97_Port_Init(void);
void AC97_Port_Return(void);
// AC97 Controller configuration
void AC97_Controller_State(void);
void AC97_Init(void);
// AC97 CODEC control
unsigned short AC97_Codec_Cmd(unsigned char CMD_Read, unsigned char CMD_Offset, unsigned short CMD_Data);
void AC97_CodecInit_PCMOut(unsigned short AC97_fs);
void AC97_CodecInit_PCMIn(unsigned short AC97_fs);
void AC97_CodecInit_MICIn(unsigned short AC97_fs);
void AC97_CodecInit_PD(void);
void AC97_CodecExit_PCMOut(void);
void AC97_CodecExit_PCMIn(unsigned short DACs_off);
void AC97_CodecExit_MICIn(unsigned short DACs_off);
void PCM_In_Volume( unsigned char Up_Down_Volume);
void PCM_Out_Volume( unsigned char Up_Down_Volume);
void Download_PCM_File(void);
// AC97 data in/out function
void AC97_PCMout_DMA1(unsigned int PCM_Size);
void AC97_PCMout_INT(unsigned int PCM_Size);
void AC97_PCMin_DMA2(unsigned int PCM_Size);
void AC97_PCMin_INT(unsigned int PCM_Size);
void AC97_MICin_DMA3(unsigned int MIC_Size);
void AC97_MICin_INT(unsigned int PCM_Size);
static void __irq DMA1_Play_Done(void);
static void __irq DMA2_Rec_Done(void);
static void __irq DMA3_Rec_Done(void);
void __irq AC97_Codec_Ready(void);
void __irq Irq_AC97_PCMout(void);
void __irq Irq_AC97_PCMin(void);
void __irq Irq_AC97_MICin(void);
static void __irq IsrWatchdog(void);
void __irq RxInt(void);
// other library
unsigned short AC97_Select_SamplingRate(void);
float delay_func(unsigned short num_delay);
void * func_ac97_test[][2]=
{
//AC97 Function Test Item
(void *)Powerdown_Test_AC97, "AC97 Power Down ",
(void *)PCM_Out_Test_AC97, "Play Wave file",
(void *)PCM_In_Out_Test_AC97, "Record Sound via LineIn and Play it ",
(void *)MICin_Test_AC97, "Record Voice via MIC and Play it ",
(void *)Reset_Test_AC97, "AC97 Reset Timing Check ",
0,0
};
void Test_AC97(void)
{
int i;
AC97_Port_Init();
while(1)
{
i=0;
printf("\n\n==================== AC97 Function Test ====================\n\n");
while(1)
{ //display menu
printf("%2d:%s",i,func_ac97_test[i][1]);
i++;
if((int)(func_ac97_test[i][0])==0)
{
printf("\n");
break;
}
if((i%2)==0)
printf("\n");
}
printf("\n============================================================");
printf("\nSelect #Item or Press enter key to exit:");
i = GetIntNum();
if(i==-1) break; // return.
if(i>=0 && (i<(sizeof(func_ac97_test)/8)) ) // select and execute...
( (void (*)(void)) (func_ac97_test[i][0]) )();
}
rAC_GLBCTRL = 0;
}
//============================== [ AC97 Drivers ] ===============================
void AC97_Port_Init(void)
{
//Push AC97 GPIO port configuration
save_AC97_rGPEDAT=rGPEDAT;
save_AC97_rGPECON=rGPECON;
save_AC97_rGPEUDP=rGPEUDP;
printf(" Which pads would you select for AC97? \n 1) muxed IIS pads 2) muxed SD pads\n");
if (getchar()=='2')
{
//---------------------------------------------------------------------
//PORT E GROUP
//Ports : GPE4 GPE3 GPE2 GPE1 GPE0
//Signal : AC97 SDO AC97 SDI AC97 BITCLK AC97 SYNC AC97 RESETn
//Binary : 11, 11, 11, 11, 11
//---------------------------------------------------------------------
rGPECON |= (0x3ff<<10); // GPE[10:6]=> AC97 function muxed SD
rGPEUDP |= (0x3ff<<10); // The pull up function is disabled GPE[10:6]
rGPECON &= ~(0x3ff); // GPE[4:0]=> AC97 function muxed IIS
rGPEUDP |= 0x1f; // The pull up function is disabled GPE[4:0]
}
else
{
//---------------------------------------------------------------------
//PORT E GROUP
//Ports : GPE4 GPE3 GPE2 GPE1 GPE0
//Signal : AC97 SDO AC97 SDI AC97 BITCLK AC97 SYNC AC97 RESETn
//Binary : 11, 11, 11, 11, 11
//---------------------------------------------------------------------
rGPECON &= ~(0x3ff<<10); // GPE[10:6]=> AC97 function muxed SD
rGPEUDP |= (0x3ff<<10); // The pull up function is disabled GPE[10:6]
rGPECON |= 0x3ff; // GPE[4:0]=> AC97 function muxed IIS
rGPEUDP |= 0x1f; // The pull up function is disabled GPE[4:0]
}
}
void AC97_Port_Return(void)
{
//Pop AC97 GPIO port configuration
rGPECON=save_AC97_rGPECON;
rGPEDAT=save_AC97_rGPEDAT;
rGPEUDP=save_AC97_rGPEUDP;
}
void AC97_Controller_State(void)
{
unsigned char state;
state=(unsigned char)(rAC_GLBSTAT);
switch(state)
{
case 0:
printf("AC97 Controller State: Idle\n");
break;
case 1:
printf("AC97 Controller State: Init\n");
break;
case 2:
printf("AC97 Controller State: Ready\n");
break;
case 3:
printf("AC97 Controller State: Active\n");
break;
case 4:
printf("AC97 Controller State: LP\n");
break;
case 5:
printf("AC97 Controller State: Warm\n");
break;
default:
break;
}
}
void AC97_Init(void)
{
int i=0;
printf("\nAC97 Initialization...\n");
//Cold Reset
rAC_GLBCTRL = 0x1; // controller and codec cold reset
Delay(1000); // delay for controller safety reset
rAC_GLBCTRL = 0x0; // controller and codec normal mode
Delay(1000);
rAC_GLBCTRL = 0x1;
Delay(1000);
rAC_GLBCTRL = 0x0;
Delay(1000);
//AC-link On
rAC_GLBCTRL = (1<<2);
Delay(1000);
AC97_Controller_State();
//Transfer data enable using AC-link
rAC_GLBCTRL |= (1<<3); // AC97 Data transfer active
Delay(1000);
AC97_Controller_State();
printf("\nAC97-Link On...\n");
//Codec Ready Check using Codec Ready Interrupt
Codec_Ready_Irq =0;
pISR_WDT_AC97 = (unsigned)AC97_Codec_Ready;
ClearPending(BIT_WDT_AC97);
rSUBSRCPND=(BIT_SUB_AC97);
rINTMSK=~(BIT_WDT_AC97);
rINTSUBMSK=~(BIT_SUB_AC97);
rAC_GLBCTRL |= 0x400000;
while(!Codec_Ready_Irq)
{
printf(".");
Delay(3000);
i++;
if(i==20)
break;
}
printf("\n");
if(i==20)
{
printf("\nAC97 codec is not ready.");
printf("\nCheck on connection between S3C2460 and AC97 CODEC.\n");
printf("\nBye. ");
Codec_Ready = 0;
}
}
unsigned short AC97_Codec_Cmd(unsigned char CMD_Read, unsigned char CMD_Offset, unsigned short CMD_Data)
{
unsigned short Codec_Stat;
if(CMD_Read == 0)
{
rAC_CODEC_CMD = (0<<23)|(CMD_Offset<<16)|(CMD_Data<<0);
delay_func(2); //32 us delay
return 1;
}
else if (CMD_Read ==1)
{
rAC_CODEC_CMD = (1<<23)|(CMD_Offset<<16)|(CMD_Data<<0);
Delay(1000);
Codec_Stat = (unsigned short)(rAC_CODEC_STAT & 0xFFFF);
Delay(1000);
return Codec_Stat;
}
else
return 0;
}
void AC97_CodecInit_PD(void)
{
printf("\nAC97 Codec Soft Reset\n");
AC97_Codec_Cmd(0,0x00,0x683F); //Codec Soft Reset : 16bit In/Out (stac9766/67)
printf("AC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
void AC97_CodecInit_PCMIn( unsigned short AC97_fs)
{
AC97_Codec_Cmd(0,0x00,0x683F); //codec soft reset
AC97_Codec_Cmd(0,0x26,(1<<9)); //all power on except DAC Block
printf("\nAC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
AC97_Codec_Cmd(0,0x2A,0x0001); //variable rate enable
printf("VRA Enable(1)/Disable(0): 0x%x\n",(0x1&AC97_Codec_Cmd(1,0x2A,0x0001)));
if(AC97_fs==48000){
//ADC Sampling frequency 48kHz
AC97_Codec_Cmd(0,0x32,0xbb80);
}
else if(AC97_fs==44100){
//ADC Sampling frequency 44.1kHz
AC97_Codec_Cmd(0,0x32,0xac44);
}
else if(AC97_fs==22050){
//ADC Sampling frequency 22.05kHz
AC97_Codec_Cmd(0,0x32,0x5622);
}
else if(AC97_fs==8000){
//ADC Sampling frequency 8kHz
AC97_Codec_Cmd(0,0x32,0x1F40);
}
AC97_Codec_Cmd(0,0x10,0x1010); //line in volume on
//* khs.050504
//* removed because seem that this is not necessary
//AC97_Codec_Cmd(0,0x6e,0x0000); //All Analog Mode, ADC Input select => left slot3, right slot4
AC97_Codec_Cmd(0,0x1a,0x0505); //record source select => Stereo Mix
AC97_Codec_Cmd(0,0x1c,0x0909); //record gain is initial
//* khs.050504
//* removed because seem that this is not necessary
//AC97_Codec_Cmd(0,0x78,0x0001); //ADC HPF Bypass
AC97_Codec_Cmd(0,0x20,0x0000); //General Reg.
Input_Volume = AC97_Codec_Cmd(1,0x10,0x0000); //Line In volume
printf("Current Line-In Volume level : 0x%04x\n",Input_Volume);
}
void AC97_CodecInit_PCMOut( unsigned short AC97_fs)
{
AC97_Codec_Cmd(0,0x00,0x683F); //codec soft reset
AC97_Codec_Cmd(0,0x2A,0x0001); //variable rate enable
//printf("\nVRA Enable(1)/Disable(0): 0x%x\n", (0x1&AC97_Codec_Cmd(1,0x2A,0x0001)));
if(AC97_fs==48000){
//DAC Sampling frequency 48kHz
AC97_Codec_Cmd(0,0x2C,0xbb80);
}
else if(AC97_fs==44100){
//DAC Sampling frequency 44.1kHz
AC97_Codec_Cmd(0,0x2C,0xac44);
}
else if(AC97_fs==22050){
//DAC Sampling frequency 22.05kHz
AC97_Codec_Cmd(0,0x2C,0x5622);
}
else if(AC97_fs==8000){
//DAC Sampling frequency 22.05kHz
AC97_Codec_Cmd(0,0x2C,0x1F40);
}
AC97_Codec_Cmd(0,0x26, (1<<8)); // all power on except ADC blcok
printf("AC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
AC97_Codec_Cmd(0,0x18,0x0000); // PCM out volume on
AC97_Codec_Cmd(0,0x20,0x0000); // general purpose
AC97_Codec_Cmd(0,0x04,0x1A1A); // Aux out(HP out) volume on
Output_Volume = AC97_Codec_Cmd(1,0x04,0x00000); //HP out volume
printf("Current Headphone Volume level : 0x%04x\n",Input_Volume);
}
void AC97_CodecInit_MICIn(unsigned short AC97_fs)
{
AC97_Codec_Cmd(0,0x00,0x683F); //codec soft reset
AC97_Codec_Cmd(0,0x2A,0x0001); //variable rate enable
printf("VRA Enable(1)/Disable(0): 0x%x\n",(0x1&AC97_Codec_Cmd(1,0x2A,0x0001)));
if(AC97_fs==48000){
//ADC Sampling frequency 48kHz
AC97_Codec_Cmd(0,0x32,0xbb80);
}
else if(AC97_fs==44100){
//ADC Sampling frequency 44.1kHz
AC97_Codec_Cmd(0,0x32,0xac44);
}
else if(AC97_fs==22050){
//ADC Sampling frequency 22.05kHz
AC97_Codec_Cmd(0,0x32,0x5622);
}
else if(AC97_fs==8000){
//ADC Sampling frequency 8kHz
AC97_Codec_Cmd(0,0x32,0x1F40);
}
AC97_Codec_Cmd(0,0x26,(1<<9)); //all power on except DAC Block
printf("\nAC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
AC97_Codec_Cmd(0,0x20,0x0000); //MIC1 Selected
AC97_Codec_Cmd(0,0x6e,0x0024); //ADC Input Slot => left slot6, right slot9, MIC GAIN VAL =1
AC97_Codec_Cmd(0,0x0e,0x0040); //BOOSTEN =1
AC97_Codec_Cmd(0,0x1a,0x0000); //Left, Right => MIC
AC97_Codec_Cmd(0,0x1c,0xff);
AC97_Codec_Cmd(0,0x78,0x0001); //ADC HPF Bypass
Input_Volume = AC97_Codec_Cmd(1,0x1c,0x0000); //Record Volume
}
void AC97_CodecExit_PCMOut(void)
{
//DACs off
printf("\n\n=>DACs off PR1\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9));
AC97_Controller_State();
printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Analog off
printf("\n=>Analog off PR2\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10));
AC97_Controller_State();
printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Digital I/F off
printf("\n=>Digital I/F off PR4\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
void AC97_CodecExit_PCMIn(unsigned short DACs_off)
{
//ADCs off
printf("\n\n=>ADCs off PR0\n");
AC97_Codec_Cmd(0,0x26,(1<<8));
AC97_Controller_State();
printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
if(DACs_off == 1)
{
//DACs off
printf("\n\n=>DACs off PR1\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9));
AC97_Controller_State();
printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
//Analog off
printf("\n=>Analog off PR2\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10));
AC97_Controller_State();
printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Digital I/F off
printf("\n=>Digital I/F off PR4\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
void AC97_CodecExit_MICIn(unsigned short DACs_off)
{
//ADCs off
printf("\n\n=>ADCs off PR0\n");
AC97_Codec_Cmd(0,0x26,(1<<8));
AC97_Controller_State();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -