680 lines
16 KiB
C
680 lines
16 KiB
C
/***************************************************************************
|
|
* Name:ssp.c *
|
|
* Description: SSP C library routine *
|
|
* Author: *
|
|
****************************************************************************/
|
|
#include "common_include.h"
|
|
#include "Driver_Common.h"
|
|
#include "kdrv_i2s.h"
|
|
|
|
|
|
//fLib_ssp *SSPDevice[] ={0, (fLib_ssp *) CPE_SSP1_BASE,
|
|
// (fLib_ssp *) CPE_I2S_BASE,(fLib_ssp *)CPE_AC97_BASE,(fLib_ssp *) CPE_SSP2_BASE};
|
|
|
|
/*
|
|
PLL=24.576M
|
|
FPclk(For 6631)=24.576/2=12.288M
|
|
FPclk(For AD73311)=24.576/8=3.072M
|
|
|
|
FSclk=8K or 32K
|
|
fBclk=FSclk*48 or FSclk*64 stuff_bit=48/2-16=8 or 64/2-16=16
|
|
|
|
FBclk= Fsclk*48(64)=Fpclk/2*(SCLK_DIV+1)
|
|
|
|
ex: Fsclk=8k Fpclk=3072K SCLK_DIV=(3072K/8K*48(64)/2)-1=3
|
|
*/
|
|
/*
|
|
PLL=24.576M
|
|
FMclk(For AC97 Winbond 83972d)=24.576M
|
|
FBclk=12.288M
|
|
|
|
FSclk=48K(AC97)
|
|
|
|
FBclk= Fsclk*256=FMclk/2*(SCLK_DIV+1)
|
|
*/
|
|
|
|
|
|
int TxFIFOLen = 0;
|
|
int RxFIFOLen = 0;
|
|
|
|
void fLib_I2S_Init(u32 base_address, u32 codec, SSP_MODE_T mode)
|
|
{
|
|
u32 data;
|
|
unsigned int master_slave;
|
|
|
|
|
|
if(mode == SSP_AS_MASTER)
|
|
master_slave = SSP_OPM_MSST;
|
|
else
|
|
master_slave = SSP_OPM_SLST;
|
|
|
|
if( codec == W6631TS_I2S )
|
|
{
|
|
// FDIST = 1, 24 bits, padding 7 bits, word_length = 16 bits
|
|
// SSP main clock input clock = source clock / 2
|
|
// outw(SSPCK_BASE,0x00);
|
|
data = I2S_Format | 0x100;
|
|
outw(base_address + SSP_CONTROL0,data);
|
|
fLib_SetSSPOPMode(base_address, master_slave);
|
|
fLib_SetSSPDataLen(base_address,15);
|
|
fLib_SetSSPpaddingDataLen(base_address,6);
|
|
fLib_SetSSPClkdiv(base_address,3);
|
|
}
|
|
else if ( codec == UDA1345TS_I2S )
|
|
{
|
|
//UDA1345TS's distance between fram/sync and first data ==> FSDIST = 1
|
|
// 16 bits, MSB first, SSP_DATAJUSTIFY set to 1 ==> pad data in the front of serial data
|
|
// 16.9344MHz clock => 22.05K sample rate
|
|
//outw(SSPCK_BASE,0x00); //dvided 2
|
|
data = I2S_Format | 0x100 | SSP_DATAJUSTIFY;// frame sync must shift 1 bits when I2S mode
|
|
outw(base_address + SSP_CONTROL0,data);
|
|
fLib_SetSSPOPMode(base_address, master_slave);
|
|
fLib_SetSSPDataLen(base_address,0xF);
|
|
fLib_SetSSPClkdiv(base_address,0x3);
|
|
}
|
|
else if ( codec == NORMAL_I2S )
|
|
{
|
|
// 16 bits, FDIST = 1, padding data in the back of serial data
|
|
// 16.9344MHz clock => 22.05K sample rate
|
|
// outw(SSPCK_BASE,0x00); //dvided 2
|
|
data = I2S_Format | 0x100;
|
|
outw(base_address + SSP_CONTROL0,data);
|
|
fLib_SetSSPOPMode(base_address, master_slave);
|
|
fLib_SetSSPDataLen(base_address,0xF);
|
|
fLib_SetSSPClkdiv(base_address,0x5);
|
|
}
|
|
else if ( codec == FSA0AC108_I2S )
|
|
{
|
|
// 16 data bits, 16 padding data bits
|
|
// FDIST = 1, padding data in the back of serial data
|
|
// 12.288MHz clock
|
|
data = I2S_Format | 0x100 | SSP_FSPO_LOW;
|
|
outw(base_address + SSP_CONTROL0,data);
|
|
fLib_SetSSPOPMode(base_address, master_slave); /* ssp as master */
|
|
fLib_SetSSPDataLen(base_address,0xF);
|
|
fLib_SetSSPpaddingDataLen(base_address, 0x10);
|
|
fLib_SetSSPClkdiv(base_address,0xB);
|
|
}
|
|
else if ( (codec == WM8510_I2S)||(codec == WM8731S_I2S) )
|
|
{
|
|
/* If SSP is set as a master, enable SCU+0x330 to allow MCLK to be given by PLL */
|
|
#if 0
|
|
if(mode == SSP_AS_MASTER)
|
|
vLib_LeWrite32(SCU_FTSCU100_PA_BASE + 0x330, 1);
|
|
else
|
|
vLib_LeWrite32(SCU_FTSCU100_PA_BASE + 0x330, 0);
|
|
#endif
|
|
// 16 data bits, 16 padding data bits
|
|
// FDIST = 1, padding data in the back of serial data
|
|
// 12.288MHz clock
|
|
data = I2S_Format | 0x100 | SSP_FSPO_LOW;
|
|
outw(base_address + SSP_CONTROL0,data);
|
|
fLib_SetSSPOPMode(base_address, master_slave);
|
|
fLib_SetSSPDataLen(base_address,0xF);
|
|
|
|
if(mode == SSP_AS_MASTER)
|
|
{
|
|
/*
|
|
As a master, SSP's MCLK is given by PLL (=12.288MHz) with SCU_FTSCU100_PA_BASE + 0x330 = 1.
|
|
Then, SCLK/BCLK (=3.072MHz) is generated by setting divider (SCLKDIV) to 1
|
|
and outputs it to codec (WM8731) as a slave, so 16-bit padding is needed for 48KHz-16bit stereo data.
|
|
48K (sample rate) * 32 (bit resolution + padding per channel) * 2 (left and right channels) = 3.072M
|
|
*/
|
|
fLib_SetSSPClkdiv(base_address,0x01);
|
|
fLib_SetSSPpaddingDataLen(base_address, 0x10);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
As a slave, SSP whose SCLK/BCLK (=3.072MHz) are given by external codec (WM8731),
|
|
so 16-bit padding is needed for 48KHz-16bit stereo data.
|
|
48K (sample rate) * 32 (bit resolution + padding per channel) * 2 (left and right channels) = 3.072M
|
|
*/
|
|
fLib_SetSSPpaddingDataLen(base_address, 0x10);
|
|
}
|
|
|
|
}
|
|
else if( codec == WM9081_I2S)
|
|
{
|
|
if(mode == SSP_AS_SLAVE)
|
|
{
|
|
/*
|
|
SCLK (BCLK) and FS (LRCLK or sample rate) of SSP010, as SLAVE, are given by WM9081 codec as MASTER where
|
|
FS = 48KHz
|
|
SCLK = FS * 16 (bit resolution per channel) * 2 (left and right channels) = 1.536MHz
|
|
|
|
SSPCLK is input by internal PLL at 12.288MHz, which suits the minimum ratio of
|
|
SSPCLK/SCLK (12.288MHz/1.536MHz >= 6)
|
|
*/
|
|
|
|
/* Set SCU+0x330 to 1 to enable PLL to generate 12.288 MHz for SSPCLK of SSP010 */
|
|
vLib_LeWrite32(SCU_FTSCU100_PA_BASE + 0x330, 1);
|
|
|
|
/* I2S format, FDIST = 1, frame sync active low */
|
|
data = I2S_Format | 0x100 | SSP_FSPO_LOW;
|
|
outw(base_address + SSP_CONTROL0,data);
|
|
|
|
/* Slave stereo mode */
|
|
fLib_SetSSPOPMode(base_address, master_slave);
|
|
// 16 data bits, no padding
|
|
fLib_SetSSPDataLen(base_address,0xF);
|
|
fLib_SetSSPpaddingDataLen(base_address, 0x0);
|
|
}
|
|
}
|
|
else if ( codec == PCM3793_I2S )
|
|
{
|
|
data = I2S_Format | 0x100 | SSP_FSPO_LOW;
|
|
outw(base_address + SSP_CONTROL0,data);
|
|
fLib_SetSSPOPMode(base_address, master_slave);
|
|
fLib_SetSSPDataLen(base_address,0xF);
|
|
fLib_SetSSPClkdiv(base_address,0x3);
|
|
}
|
|
}
|
|
|
|
void fLib_SetSSPFrame(u32 base_address,u32 frame)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL0);
|
|
data &= 0xFFF;
|
|
data |= frame;
|
|
outw(base_address + SSP_CONTROL0, data);
|
|
}
|
|
|
|
|
|
void fLib_SetSSPFramePolar(u32 base_address,u32 polar)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL0);
|
|
data &= ~0x20;
|
|
data |= polar;
|
|
outw(base_address + SSP_CONTROL0, data);
|
|
}
|
|
|
|
|
|
void fLib_SetSSPOPMode(u32 base_address,u32 mode)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL0);
|
|
data &= ~0xC;
|
|
data |= mode;
|
|
outw(base_address + SSP_CONTROL0, data);
|
|
}
|
|
|
|
|
|
void fLib_SetSSPDataLen(u32 base_address,u32 len)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL1);
|
|
data &= ~ SSP_SDL;
|
|
data |= len << 16;
|
|
outw(base_address + SSP_CONTROL1, data);
|
|
}
|
|
|
|
void fLib_SetSSPpaddingDataLen(u32 base_address,u32 len)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL1);
|
|
data &= ~ SSP_PDL;
|
|
data |= len << 24;
|
|
outw(base_address + SSP_CONTROL1, data);
|
|
}
|
|
|
|
void fLib_SetSSPClkdiv(u32 base_address,u32 divider)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL1);
|
|
data &= ~ SSP_CLKDIV;
|
|
data |= divider;
|
|
outw(base_address + SSP_CONTROL1, data);
|
|
}
|
|
|
|
|
|
void fLib_SSPClearTxFIFO(u32 base_address)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL2);
|
|
data |= SSP_TXFCLR;
|
|
outw(base_address + SSP_CONTROL2, data);
|
|
}
|
|
|
|
|
|
void fLib_SSPClearRxFIFO(u32 base_address)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL2);
|
|
data |= SSP_RXFCLR;
|
|
outw(base_address + SSP_CONTROL2, data);
|
|
}
|
|
|
|
|
|
void fLib_WriteSSP(u32 base_address,u32 data)
|
|
{
|
|
outw(base_address + SSP_DATA, data);
|
|
}
|
|
|
|
|
|
u32 fLib_ReadSSPStatus(u32 base_address)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_STATUS);
|
|
return data;
|
|
}
|
|
|
|
|
|
u32 fLib_ReadSSP(u32 base_address)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_DATA);
|
|
return data;
|
|
}
|
|
|
|
void fLib_SetSSPSCLKPO(u32 base_address,u32 spolarity)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL0);
|
|
data &= ~0x2;
|
|
data |= spolarity;
|
|
outw(base_address + SSP_CONTROL0, data);
|
|
}
|
|
|
|
|
|
void fLib_SetSSPSCLKPH(u32 base_address,u32 sphase)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_CONTROL0);
|
|
data &= ~0x1;
|
|
data |= sphase;
|
|
outw(base_address + SSP_CONTROL0, data);
|
|
}
|
|
|
|
|
|
u32 fLib_ReadSSPIntStatus(u32 base_address)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_INT_STATUS);
|
|
return data;
|
|
}
|
|
|
|
|
|
void fLib_SetSSP_TXFIFO(u32 base_address,u32 threshold,u32 underrun)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_INT_CONTROL);
|
|
|
|
if (threshold)
|
|
data |= SSP_TFIEN;
|
|
else
|
|
data &= ~SSP_TFIEN;
|
|
|
|
if (underrun)
|
|
data |= SSP_TFURIEN;
|
|
else
|
|
data &= ~SSP_TFURIEN;
|
|
|
|
outw(base_address + SSP_INT_CONTROL, data);
|
|
}
|
|
|
|
void fLib_SetSSP_RXFIFO(u32 base_address,u32 threshold,u32 underrun)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_INT_CONTROL);
|
|
|
|
if (threshold)
|
|
data |= SSP_RFIEN;
|
|
else
|
|
data &= ~SSP_RFIEN;
|
|
|
|
if (underrun)
|
|
data |= SSP_RFORIEN;
|
|
else
|
|
data &= ~SSP_RFORIEN;
|
|
|
|
outw(base_address + SSP_INT_CONTROL, data);
|
|
}
|
|
|
|
void fLib_SetSSP_DMA(u32 base_address,u32 trans,u32 rec)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_INT_CONTROL);
|
|
|
|
if (trans)
|
|
data |= SSP_TXDMAEN;
|
|
else
|
|
data &= ~SSP_TXDMAEN;
|
|
|
|
if (rec)
|
|
data |= SSP_RXDMAEN;
|
|
else
|
|
data &= ~SSP_RXDMAEN;
|
|
|
|
outw(base_address + SSP_INT_CONTROL, data);
|
|
}
|
|
|
|
|
|
void fLib_SetSSP_FIFO_Threshold(u32 base_address,u32 trans_len,u32 rec_len)
|
|
{
|
|
u32 ctrl;
|
|
ctrl = inw(base_address + SSP_INT_CONTROL);
|
|
|
|
ctrl &= ~0x0001FF80; //bessel:todo:length start with 7th bit not 8bit
|
|
//ctrl |= ((trans_len << 12) + (rec_len << 8)) & 0x0000FF00;
|
|
ctrl |= ((trans_len << 12) + (rec_len << 7));
|
|
|
|
outw(base_address + SSP_INT_CONTROL, ctrl);
|
|
}
|
|
|
|
|
|
void fLib_SetSSP_WarmReset(u32 base_address)
|
|
{
|
|
u32 ctrl;
|
|
|
|
outw(base_address + SSP_CONTROL2, SSP_ACWRST | SSP_TXDOE);
|
|
do
|
|
{
|
|
ctrl = inw(base_address + SSP_CONTROL2);
|
|
}while((ctrl & SSP_ACWRST) != 0);
|
|
}
|
|
|
|
void fLib_SetSSP_ColdReset(u32 base_address)
|
|
{
|
|
u32 ctrl;
|
|
|
|
outw(base_address + SSP_CONTROL2, SSP_ACCRST | SSP_TXDOE); //
|
|
do
|
|
{
|
|
ctrl = inw(base_address + SSP_CONTROL2);
|
|
}while((ctrl & SSP_ACCRST) != 0);
|
|
}
|
|
|
|
|
|
void fLib_SetSSP_Enable(u32 base_address,int enable)
|
|
{
|
|
u32 ctrl;
|
|
|
|
ctrl = inw(base_address + SSP_CONTROL2);
|
|
if(enable)
|
|
ctrl |= (SSP_SSPEN | SSP_TXDOE | SSP_TXEN | SSP_RXEN);//TXDOE is a must; otherwise, no sound at all to output
|
|
else
|
|
ctrl &= ~(SSP_SSPEN + SSP_TXDOE | SSP_TXEN | SSP_RXEN);
|
|
|
|
outw(base_address + SSP_CONTROL2, ctrl);
|
|
}
|
|
|
|
void fLib_SetSSP_IntMask(u32 base_address,int Mask)
|
|
{
|
|
u32 ctrl;
|
|
ctrl = inw(base_address + SSP_INT_CONTROL);
|
|
ctrl &= ~0x3F;
|
|
ctrl |= Mask;
|
|
outw(base_address + SSP_INT_CONTROL, ctrl);
|
|
}
|
|
|
|
u32 fLib_SSP_GetTxFIFOLen(u32 base_address)
|
|
{
|
|
u32 len;
|
|
len = (inw(base_address + SSP_INFO)&SSP_TXFIFO_DEPTH);
|
|
TxFIFOLen = (len >> 16) + 1;
|
|
return TxFIFOLen;
|
|
}
|
|
|
|
u32 fLib_SSP_GetRxFIFOLen(u32 base_address)
|
|
{
|
|
u32 len;
|
|
len = (inw(base_address + SSP_INFO)&SSP_RXFIFO_DEPTH);
|
|
RxFIFOLen = (len >> 8) + 1;
|
|
|
|
return RxFIFOLen;
|
|
}
|
|
|
|
|
|
u32 fLib_SSP_GetRxFIFOValidEntries(u32 base_addr)
|
|
{
|
|
return ((fLib_ReadSSPStatus(base_addr) & SSP_RFVE) >> 4);
|
|
}
|
|
|
|
|
|
void fLib_AC97_SetSlotValidReg(u32 base_address,u32 SlotValid)
|
|
{
|
|
outw(base_address + SSP_ACLINK_SLOT_VALID, SlotValid);
|
|
}
|
|
|
|
void fLib_InitAC97(u32 base_address)
|
|
{
|
|
// outw(SSPCK_BASE, 0xF00);
|
|
|
|
fLib_SetSSPFrame(base_address,AC97_Format);
|
|
|
|
fLib_SSP_GetTxFIFOLen(base_address);
|
|
fLib_SSP_GetRxFIFOLen(base_address);
|
|
|
|
fLib_SetSSP_ColdReset(base_address);
|
|
|
|
fLib_SetSSP_Enable(base_address,false);
|
|
|
|
fLib_SetSSP_IntMask(base_address,0);
|
|
|
|
fLib_SetSSP_FIFO_Threshold(base_address,4,4);
|
|
|
|
}
|
|
|
|
void fLib_AC97_WriteData(u32 base_address,u32 *data, u32 Len)
|
|
{
|
|
u32 tx_cnt;
|
|
|
|
while(Len != 0)
|
|
{
|
|
tx_cnt = (inw(base_address + SSP_STATUS) & SSP_TFVE) >> 12;
|
|
|
|
for(; tx_cnt < TxFIFOLen; tx_cnt++, data++, Len--)
|
|
{
|
|
if(Len == 0)
|
|
return ;
|
|
|
|
outw(base_address + SSP_DATA, *data);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void fLib_AC97_ReadData(u32 base_address,u32 *data, u32 Len)
|
|
{
|
|
u32 rx_cnt;
|
|
|
|
while(Len != 0)
|
|
{
|
|
rx_cnt = (inw(base_address + SSP_STATUS) & SSP_RFVE) >> 4;
|
|
|
|
for(; rx_cnt > 0; rx_cnt--, data++, Len--)
|
|
{
|
|
if(Len == 0)
|
|
return;
|
|
|
|
*data = inw(base_address + SSP_DATA);
|
|
}
|
|
}
|
|
}
|
|
u32 fLib_ReadSSP32Bit(u32 base_address)
|
|
{
|
|
u32 data;
|
|
|
|
data = inw(base_address + SSP_DATA);
|
|
return data;
|
|
}
|
|
u32 fLib_AC97_ReadOneWordData(u32 base_address)
|
|
{
|
|
while(!(inw(base_address + SSP_STATUS) & SSP_RFVE))
|
|
;
|
|
|
|
return inw(base_address + SSP_DATA);
|
|
}
|
|
|
|
|
|
int fLib_AC97_ReadRegister(u32 base_address,u32 Reg_Index, u16 *data)
|
|
{
|
|
u32 TxBuf[3], RxBuf[3];
|
|
|
|
TxBuf[0] = 0xE000;
|
|
TxBuf[1] = 0x80000+(Reg_Index<<12);
|
|
TxBuf[2] = 0;
|
|
|
|
fLib_SSPClearTxFIFO(base_address);
|
|
fLib_SSPClearRxFIFO(base_address);
|
|
|
|
fLib_AC97_SetSlotValidReg(base_address,0x7);
|
|
|
|
fLib_AC97_WriteData(base_address,TxBuf, 3);
|
|
|
|
fLib_SetSSP_Enable(base_address,true);
|
|
|
|
while(1)
|
|
{
|
|
fLib_AC97_ReadData(base_address,RxBuf, 1);
|
|
//check reg index is match
|
|
if((RxBuf[0] & 0xE000) == 0xE000)
|
|
{
|
|
fLib_AC97_ReadData(base_address,RxBuf, 1);
|
|
if(((RxBuf[0] >> 12) & 0x7f) == Reg_Index)
|
|
{
|
|
fLib_AC97_ReadData(base_address,RxBuf, 1);
|
|
*data = (RxBuf[0] >> 4) & 0x0000ffff;
|
|
}
|
|
fLib_SetSSP_Enable(base_address,false);
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int fLib_ReturnTxFIFO_Count(u32 base_address)
|
|
{
|
|
int count = 0;
|
|
|
|
count = (inw(base_address+SSP_STATUS)&SSP_TFVE)>>12;
|
|
|
|
return count;
|
|
}
|
|
|
|
int fLib_ReturnRxFIFO_Count(u32 base_address)
|
|
{
|
|
int count = 0;
|
|
|
|
count = (inw(base_address+SSP_STATUS)&SSP_RFVE)>>4;
|
|
|
|
return count;
|
|
}
|
|
|
|
int fLib_AC97_ReadRegisterEx(u32 base_address,u32 Reg_Index, u16 *data)
|
|
{
|
|
u32 TxBuf[2], RxBuf[2];
|
|
|
|
*data = 0xFFFF;
|
|
|
|
TxBuf[0] = 0x80000+(Reg_Index<<12); // Command address slot (slot1)
|
|
TxBuf[1] = 0; // Command Data port slot (slot2)
|
|
|
|
fLib_SSPClearTxFIFO(base_address);
|
|
fLib_SSPClearRxFIFO(base_address);
|
|
|
|
fLib_AC97_SetSlotValidReg(base_address,0xE000); // slot0, slot1, slot2
|
|
|
|
//##########################################################################
|
|
// when enable SSP controler, data will send immediately at the first frame,
|
|
// but receive data will be at next frame
|
|
// to make sure second frame will not send wrong data,
|
|
// we must fill 2 set of command to prevent second data to be wrong
|
|
//##########################################################################
|
|
fLib_AC97_WriteData(base_address,TxBuf, 2);
|
|
fLib_AC97_WriteData(base_address,TxBuf, 2);
|
|
|
|
fLib_SetSSP_Enable(base_address,true);
|
|
|
|
while(fLib_ReturnTxFIFO_Count(base_address)>0)
|
|
;
|
|
|
|
fLib_SetSSP_Enable(base_address,false);
|
|
|
|
// data will be in the second frame, so pump 2 fifo data first
|
|
fLib_AC97_ReadData(base_address,RxBuf, 2); // read first frame (no use frame)
|
|
|
|
// real valid data
|
|
fLib_AC97_ReadData(base_address,RxBuf, 1); // read second frame - slot1(ECHO of Command address)
|
|
if(((RxBuf[0] >> 12) & 0x7f) == Reg_Index)
|
|
{
|
|
fLib_AC97_ReadData(base_address,RxBuf, 1); // read second frame - slot2 (status data port)
|
|
*data = (RxBuf[0] >> 4) & 0x0000ffff;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void fLib_AC97_WriteRegister(u32 base_address,u32 Reg_Index, u32 data)
|
|
{
|
|
u32 TxBuf[3];
|
|
|
|
TxBuf[0] = 0xE000;
|
|
TxBuf[1] = 0x00000+(Reg_Index<<12);
|
|
TxBuf[2] = data << 4;
|
|
|
|
fLib_SSPClearTxFIFO(base_address);
|
|
fLib_SSPClearRxFIFO(base_address);
|
|
fLib_AC97_SetSlotValidReg(base_address,0x7);
|
|
|
|
fLib_AC97_WriteData(base_address,TxBuf, 3);
|
|
fLib_SetSSP_Enable(base_address,true);
|
|
while(((inw(base_address+SSP_STATUS)&SSP_TFVE)>>12)>0)
|
|
;
|
|
|
|
fLib_SetSSP_Enable(base_address,false);
|
|
}
|
|
|
|
void fLib_AC97_WriteRegisterEx(u32 base_address,u32 Reg_Index, u32 data)
|
|
{
|
|
u32 TxBuf[2];
|
|
|
|
TxBuf[0] = 0x00000+(Reg_Index<<12);
|
|
TxBuf[1] = data << 4;
|
|
|
|
fLib_SSPClearTxFIFO(base_address);
|
|
fLib_SSPClearRxFIFO(base_address);
|
|
fLib_AC97_SetSlotValidReg(base_address,0xE000); // slot0, slot1, slot2
|
|
|
|
fLib_AC97_WriteData(base_address,TxBuf, 2);
|
|
fLib_SetSSP_Enable(base_address,true);
|
|
|
|
while(fLib_ReturnTxFIFO_Count(base_address)>0)
|
|
;
|
|
|
|
fLib_SetSSP_Enable(base_address,false);
|
|
|
|
}
|
|
|
|
u32 fLib_SSP_busy(u32 base_addr)
|
|
{
|
|
return (((fLib_ReadSSPStatus(base_addr) ) >> 2) & 0x1);
|
|
}
|
|
|
|
void fLib_SetSSP_SDL_Write(u32 base_address,u32 len,u32 w_data)
|
|
{
|
|
while (fLib_SSP_busy(base_address))
|
|
;
|
|
fLib_SetSSPDataLen(base_address,len);
|
|
fLib_WriteSSP(base_address,w_data);
|
|
}
|