📄 codec.c
字号:
/*++
Copyright (c) 2001, 2002 BSQUARE Corporation. All rights reserved.
Module Name:
codec.c
Module Description:
This module contains the implementation of the codec
routines.
Author:
Benny Ng 25-June-2001
Revision History:
Yuqun Cao 16-Jan-2002
1. Add support of cs4201 codec for Aruba platform.
The old LM4548 codec is still supported.
2. Add delay between reads from CODEC per Aruba errata.
--*/
#include "chip.h"
#include "audio.h"
#include "ac97.h"
#include "cs4201.h"
//\#pragma optimize("",off)
//*TSAT* 27-Dec-2002 Turn on debug messages
//#undef DEBUGMSG
//#define DEBUGMSG(cond, msg) RETAILMSG(1, msg)
static unsigned short int VolMatrix[0x64];
APB_RTC_REGS* RTCRegPtr = NULL;
APB_GPIO_REGS* GPIORegPtr=(PVOID) APB_GPIO_REGS_BASE;
#define DEFAULT_VOLUME 0x0000
#define DEFAULT_RATE 0xAC44
#define DELAY_VAL 0x5000
ULONG AAC_ReadCODECIndexRegister (APB_AAC_REGS* aacRegPtr, ULONG AC97Reg);
////////////////////////////////////////////////////////////////////////////////
//
// Name: AAC_Slot1Wait
// AAC_Slot2Wait
//
// Description:
// Wait for indicator bit to be set in AAC status register.
//
// Parameters:
// aacRegPtr - Pointer to AAC controller within the SOC.
//
// Return Value:
// TRUE - Success if bit was set by the AAC controller
//
////////////////////////////////////////////////////////////////////////////////
BOOLEAN AAC_Slot1Wait(APB_AAC_REGS* aacRegPtr)
{
#ifdef BSP_AUDIOREADSLOT1TX // Due to a known errata a 1ms wait is used instead of a polling on the status bit
int timeoutcounter;
volatile ULONG * pAACRGIS = &(aacRegPtr->AACRGIS);
//******************************************************************************
//* Function to wait for the transmit on Slot 1 to happen correctly.
//* This prevents overwriting data while waiting to transmit
//*
//******************************************************************************
timeoutcounter = 100000000;
while(!((READ_REGISTER_ULONG(pAACRGIS)) & AAC_RGIS_SLOT1TXCOMPLETE))
{
timeoutcounter--;
if(timeoutcounter == 0)
{
DEBUGMSG(1,(TEXT("AAC_Slot1Wait() Failure.\r\n")));
// return FALSE;
}
}
#endif
Sleep(1);
return TRUE;
}
BOOLEAN AAC_Slot2Wait (APB_AAC_REGS* aacRegPtr)
{
int timeoutcounter;
volatile ULONG * pAACRGIS = &(aacRegPtr->AACRGIS);
//******************************************************************************
//* Function to wait for the data requested from the AC97 to get into Slot 2.
//*
//******************************************************************************
timeoutcounter = 100000000;
while(!((READ_REGISTER_ULONG(pAACRGIS)) & AAC_RGIS_SLOT2RXVALID))
{
timeoutcounter--;
if(timeoutcounter == 0)
{
DEBUGMSG(1,(TEXT("AAC_Slot2Wait() Failure.\r\n")));
// return FALSE;
}
}
// Sleep(1);
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
//
// Name: AC97Read
//
// Description:
// Read data through the AAC controller from the codec.
//
// Parameters:
// aacRegPtr - Pointer to AAC controller within the SOC.
// AC97Reg - Index of codec register being written.
//
// Return Value:
// ULONG - Data read from the register.
//
////////////////////////////////////////////////////////////////////////////////
ULONG AC97Read (APB_AAC_REGS* aacRegPtr, ULONG AC97Reg)
{
#if 0
int errNum;
ULONG ulTmp1;
volatile ULONG * pAACS1DATA = &(aacRegPtr->AACS1DATA);
volatile ULONG * pAACS2DATA = &(aacRegPtr->AACS2DATA);
WRITE_REGISTER_ULONG(pAACS1DATA,0x0080 | AC97Reg);
Drv_AHBBus_ExtraWrite();
if((AAC_Slot2Wait(aacRegPtr)) == FALSE) goto ErrorReturn;
ulTmp1 = READ_REGISTER_ULONG(pAACS2DATA);
errNum = 99;
ErrorReturn:
if(errNum < 99)
{
DEBUGMSG(1,(TEXT("AC97Read() failure. errNum = %d\r\n"), errNum));
}
return ulTmp1;
#else
volatile int timeout;
/* Set bit 15 high to indicate a read operation */
aacRegPtr->AACS1DATA = (ULONG) (0x0080 | AC97Reg);
timeout = 2000;
while (((aacRegPtr->AACRGIS & AAC_RGIS_SLOT2RXVALID) == 0) &&
(timeout > 0))
{
timeout--;
}
return (ULONG) aacRegPtr->AACS2DATA;
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
// Name: AC97Write
//
// Description:
// Write data through the AAC controller to the codec.
//
// Parameters:
// aacRegPtr - Pointer to AAC controller within the SOC.
// AC97Reg - Index of codec register being written.
// AC97Data - Data to be loaded into the codec register.
//
// Return Value:
// TRUE - Success if register was written correctly.
//
////////////////////////////////////////////////////////////////////////////////
BOOLEAN AC97Write (APB_AAC_REGS* aacRegPtr, ULONG AC97Reg, ULONG AC97Data)
{
#if 0
BOOLEAN RoutineSuccess = FALSE;
int errNum;
ULONG ulTmp1;
volatile ULONG * pAACS1DATA = &(aacRegPtr->AACS1DATA);
volatile ULONG * pAACS2DATA = &(aacRegPtr->AACS2DATA);
DEBUGMSG(1,(TEXT("AC97Write - aacRegPtr=0x%X, AC97Reg=0x%X, AC97Data=0x%X\r\n"), (DWORD)aacRegPtr, AC97Reg, AC97Data));
errNum=0;
//******************************************************************************
//* CodecDelay() is an artificial time delay to work-around a hardware flaw.
//* Load Slot 2 with the Data.
//* Load Slot 1 with the Register Index.
//* Set the error code number.
//* Wait for the SLOT1TXCOMPLETE flag to get set.
//*
//******************************************************************************
if ((READ_REGISTER_ULONG(&(aacRegPtr->AACRGIS)) & AAC_RGIS_CODECREADY)==0)
DEBUGMSG(1,(TEXT("Audio: Codec not ready!\r\n")));
WRITE_REGISTER_ULONG(pAACS2DATA, AC97Data);
Drv_AHBBus_ExtraWrite();
WRITE_REGISTER_ULONG(pAACS1DATA, AC97Reg);
Drv_AHBBus_ExtraWrite();
errNum=1;
if((AAC_Slot1Wait(aacRegPtr)) == FALSE) goto ErrorReturn;
WRITE_REGISTER_ULONG(pAACS1DATA, AC97Reg);
Drv_AHBBus_ExtraWrite();
errNum=2;
if((AAC_Slot2Wait(aacRegPtr)) == FALSE) goto ErrorReturn;
errNum=3;
ulTmp1 = READ_REGISTER_ULONG(pAACS2DATA);
//******************************************************************************
//* If we've written something other than the reset register and we've not read
//* back identical data, flag an error.
//* Else, set the error code number and routine status flags to pass.
//*
//******************************************************************************
if((AC97Reg != AC97_RESET) &&
(ulTmp1 != AC97Data)) goto ErrorReturn;
errNum = 99;
RoutineSuccess = TRUE;
ErrorReturn:
if(errNum < 99) {
DEBUGMSG(1,(TEXT("AC97Write() failure. errNum = %d AC97Reg=%X ulTmp1=%X AC97Data=%X \r\n"), errNum,AC97Reg,ulTmp1,AC97Data));
}
return RoutineSuccess;
#else
volatile int timeout;
/* Perform a dummy read of the slot 2 data to clear anything that
might be in it */
volatile ULONG idata = aacRegPtr->AACS2DATA;
/* Suppress unused variable warning with some compilers */
(void) idata;
/* Send the data for the register through the controller to the
CODEC */
aacRegPtr->AACS2DATA = (ULONG) AC97Data;
aacRegPtr->AACS1DATA = (ULONG) AC97Reg;
/* It takes a few microseconds for the data to get to the CODEC, so
this dummy delay allows a small bit of time for the data to get
there in the case of repeated calls to this function (which may
cause corruption if the data has been sent yet) */
timeout = 2000;
while (timeout > 0)
{
timeout--;
}
return TRUE;
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
// Name: AAC_ReadCODECIndexRegister
// AAC_WriteCODECIndexRegister
//
// Description:
// Pass-through routines.
//
// Parameters:
// aacRegPtr - Pointer to AAC controller within the SOC.
// AC97Reg - Index of codec register being written.
// Value - Data to be loaded into the codec register.
//
// Return Value:
// ULONG - Data if register was read correctly.
// TRUE - Success if register was written correctly.
//
////////////////////////////////////////////////////////////////////////////////
ULONG AAC_ReadCODECIndexRegister (APB_AAC_REGS* aacRegPtr, ULONG AC97Reg)
{
return AC97Read (aacRegPtr, AC97Reg);
}
BOOLEAN AAC_WriteCODECIndexRegister (APB_AAC_REGS* aacRegPtr, ULONG AC97Reg, ULONG Value)
{
return AC97Write (aacRegPtr, AC97Reg, Value);
}
////////////////////////////////////////////////////////////////////////////////
//
// Name: CodecDeinitialize
//
// Description:
// Deinitializes the codec.
//
// Parameters:
// None described
//
// Return Value:
// NONE
//
////////////////////////////////////////////////////////////////////////////////
VOID CodecDeinitialize(IN OUT PWAVE_DEVICE_INSTANCE WaveInstance)
{
if (WaveInstance != NULL)
{
LocalFree(WaveInstance->CodecDevice);
WaveInstance->CodecDevice = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////
//
// Name: CodecInitializeRegisters
//
// Description:
// Set the CODEC into a known state for initialization.
//
// Parameters:
// CodecDevice - Structure to identify the AAC controller in the SOC.
//
// Return Value:
// TRUE - Successful initialization.
//
////////////////////////////////////////////////////////////////////////////////
BOOLEAN CodecInitializeRegisters(IN OUT PCODEC_DEVICE CodecDevice)
{
APB_AAC_REGS* AacRegPtr;
int ErrNum;
ULONG ulVid1;
ULONG ulVid2;
int timeoutcounter;
//******************************************************************************
//* Sets the CODEC (LM4548, CS4201) into a known state for initialization.
//* Read the CODEC vendor and type ID. If this isn't specifically an LM4548 or
//* CS4201 CODEC, then abort initialization.
//*
//******************************************************************************
AacRegPtr = CodecDevice->AacRegPtr;
ErrNum = AC97_VENDOR_ID1;
ulVid1 = AAC_ReadCODECIndexRegister(AacRegPtr, AC97_VENDOR_ID1);
ulVid2 = AAC_ReadCODECIndexRegister(AacRegPtr, AC97_VENDOR_ID2);
DEBUGMSG(1,(TEXT("CodecInitializeRegisters, vendor id 0x%x 0x%x\r\n"), ulVid1, ulVid2));
// 0x50534304 UCB1400
if ((ulVid1 == 0x5053) &&
(ulVid2 == 0x4304))
{
DEBUGMSG(1, (TEXT("UCB1400 audio CODEC found\r\n")));
}
else if ((ulVid1 == 0x574d) &&
(ulVid2 == 0x4c03))
{
DEBUGMSG(1, (TEXT("SDK audio CODEC found\r\n")));
}
else if((ulVid1 == 0x4352) &&
(ulVid2 == 0x5949 || ulVid2 == 0x594d))
{
DEBUGMSG(1, (TEXT("CS4201 audio CODEC found\r\n")));
}
else
{
DEBUGMSG(1, (TEXT("Audio CODEC NOT recognized or NOT found!\r\n")));
goto ErrorReturn;
}
//******************************************************************************
//* Reset the Codec by writing to the reset register. (0x00)
//* Enable Variable Rate Audio mode. (0x2A)
//* This must be down before making the sample rate changes.
//* Set the DAC default sample rate to 11kHz. See CS4201 docs.
//* Set the Front DAC rate. (0x2C)
//* Set the Left/Right ADC rate (0x32)
//* Set the Volume control registers.
//* Set Headphone Output Volume (0x04)
//* Set Master Volume (0x02)
//* Mute the PC Beep Volume (0x0A)
//* Set Input Gain to PCM Output Volume (0x18)
//*
//******************************************************************************
AAC_WriteCODECIndexRegister(AacRegPtr,AC97_POWER_CONTROL,0x00);
timeoutcounter=10000;
while ( (AAC_ReadCODECIndexRegister(AacRegPtr,AC97_POWER_CONTROL) & 0x0B)!=0x000B)
{
timeoutcounter--;
if(timeoutcounter == 0)
{
DEBUGMSG(1,(TEXT("AAC not able to power up ready. AC97_POWER_CONTROL=%X\r\n"),AAC_ReadCODECIndexRegister(AacRegPtr,AC97_POWER_CONTROL)));
goto ErrorReturn;
}
}
DEBUGMSG(1,(TEXT("AAC power up ready. AC97_POWER_CONTROL=%X\r\n"),AAC_ReadCODECIndexRegister(AacRegPtr,AC97_POWER_CONTROL)));
// ErrNum = AC97_EXTENDED_AUDIO_STATUS_CONTROL;
// if (!AAC_WriteCODECIndexRegister (AacRegPtr, CS4201_ACMODECTRLREG, 0x0180)) {
// goto ErrorReturn;
// }
// ErrNum = AC97_EXTENDED_AUDIO_STATUS_CONTROL;
// if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_GENERAL_PURPOSE, 0xA000)) {
// goto ErrorReturn;
// }
ErrNum = AC97_EXTENDED_AUDIO_STATUS_CONTROL;
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_EXTENDED_AUDIO_STATUS_CONTROL, 0x0001)) {
goto ErrorReturn;
}
ErrNum = AC97_PCM_FRONT_DAC_RATE;
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_PCM_FRONT_DAC_RATE, DEFAULT_RATE)) {
goto ErrorReturn;
}
ErrNum = AC97_PCM_ADC_RATE;
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_PCM_ADC_RATE, DEFAULT_RATE)) {
goto ErrorReturn;
}
//*TSAT* 02-Jan-2003
// Cirrus CS4201 Data Sheet (CS4201_AudioCodec.pdf), Pg. 23.
// - Analog Mixer Output Volume Registers (Index 02h - 04h)
// - "If the HPCFG pin is tied 'low', register 02h controls the Headphone Volume and register 04h is a read-only register and
// always returns 0000h when 'read'."
// - On Aruba, HPCFG is tied to ground.
// ErrNum = AC97_ALT_LINE_LEVEL_OUT_VOLUME;
// if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_ALT_LINE_LEVEL_OUT_VOLUME, DEFAULT_VOLUME)) {;
// goto ErrorReturn; }
ErrNum = AC97_MASTER_VOLUME;
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_MASTER_VOLUME, DEFAULT_VOLUME)) {;
goto ErrorReturn;
}
CodecDevice->Volume = DEFAULT_VOLUME;
ErrNum = AC97_PC_BEEP_VOLUME;
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_PC_BEEP_VOLUME, 0x0008)) {; //Mute
goto ErrorReturn;
}
ErrNum = AC97_RECORD_SELECT;
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_RECORD_SELECT, 0x0404)) {; //Turn on
goto ErrorReturn;
}
ErrNum = AC97_RECORD_GAIN;
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_RECORD_GAIN, 0x0000)) {; //Turn on
goto ErrorReturn;
}
ErrNum = AC97_LINE_IN_VOLUME; // 0x0808
if (!AAC_WriteCODECIndexRegister (AacRegPtr, AC97_LINE_IN_VOLUME, 0x0000)) {; //Turn on
goto ErrorReturn;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -