📄 ac97.c
字号:
/*----------------------------------------------------------------------------------
*
* COPYRIGHT (c) 2001 by Singing Electrons, Inc. All rights reserved.
*
* Module Name : C:\se\adi\audioclass\vdsp\ac97.c
*
* Description : Contains code to communicate with the AC97 AC-Link
*
*
* Revision History : At bottom of the file.
*
*---------------------------------------------------------------------------------*/
/** include files **/
#include <sys/exception.h>
#include <sys/excause.h>
#include <defBF535.h>
#include "dtype.h"
#include "register.h"
#include "dprintf.h"
#include "dmablocks.h"
#include "ac_init.h"
#include "ac97.h"
/** local definitions **/
//This is for Eagle-35 only!
#define kLEDSet \
ZET(bPF8,1)+\
ZET(bPF9,1)+\
ZET(bPF10,1)+\
ZET(bPF11,1)+\
ZET(bPF12,1)+\
ZET(bPF13,1)+\
ZET(bPF14,1)
#define kLEDMix \
ZET(bPF8,0)+\
ZET(bPF9,1)+\
ZET(bPF10,0)+\
ZET(bPF11,1)+\
ZET(bPF12,0)+\
ZET(bPF13,1)+\
ZET(bPF14,0)
#define bACRes 15
#define kACResSet ZET(bACRes,1)
#define kACResReset ZET(bACRes,0)
// Define time constants
// (not yet bound to core clock frequency but you rather have to change here for
// now)
#define TC_1MS_300MHZ 300000
#define TC_2US_300MHZ 600
#define TC_3S_300MHZ 20000000
#define FRAME_BUFFER_LEN (16 * 2)
#define CODEC_REG_INIT_COUNT 25
#define CODEC_REG_INIT_LENGTH (CODEC_REG_INIT_COUNT * 2)
enum {
AC97_STATE_UNDEFINED = 0,
AC97_STATE_INITIALIZING_CODEC_STARTED,
AC97_STATE_INITIALIZING_CODEC_COMPLETED,
AC97_STATE_PLAY_DATA,
};
/* default settings */
USHORT gInitCodecRegs[CODEC_REG_INIT_LENGTH] =
{
REGS_RESET, 0xFFFF, // Writing any value to this reg.
// performs a register reset
MASTER_VOLUME, 0x0000, // Mute off master volume, 0 dB gain on
// L/R channels
HEAD_VOLUME, 0x0000, // Mute off headphone volume, 6 dB gain
MASTER_VOLUME_MONO, 0x8000, // Mute on mono master volume
PC_BEEP_Volume, 0x8000, // Mute on PC beep volume
PHONE_Volume, 0x8008, // Mute on phone volume, 0 dB gain
MIC_Volume, 0x8008, // Mute on MIC volume, 0 dB gain
LINE_IN_Volume, 0x8808, // Mute on LINE in vol.,0 dB gain on L/R
CD_Volume, 0x8808, // Mute on CD volume, 0 dB gain on L/R
VIDEO_Volume, 0x8808, // Mute on video volume,0 dB gain on L/R
AUX_Volume, 0x8808, // Mute on aux volume,0 dB gain on L/R
PCM_OUT_Volume, 0x0F0F, // Mute off, -10.5 dB gain
#ifndef MIC_IN
RECORD_SELECT, 0x0404, // Selected LINE in L/R as Record Select
#else
RECORD_SELECT, 0x0000, // Selected MIC1 as Record Select
#endif
RECORD_GAIN, 0x0000, // Mute off, 0 dB record gain
GENERAL_PURPOSE, 0x0000, // Codec loopback off,MIC1 selected,
// Mono output selected: Mix
// PHAT stereo off,pre-3D
THREE_D_CONTROL_REG, 0x0000, // 3D depth: 0%
POWERDOWN_CTRL_STAT, 0x0000, // Status reg. to see powered-down
// subsections
EXTEND_AUDIO_ID, 0x0001, // Read-only reg. support for variable
// rate audio
EXTEND_AUDIO_CTL, 0x0000, // Enable support for variable rate audio
SAMPLE_RATE_GENERATE_1, 0xBB80, // DAC Sample Rate 48.000 KHz
SAMPLE_RATE_GENERATE_0, 0xBB80, // ADC Sample Rate 48.000 KHz
JACK_SENSE, 0x0000, // No sense interrupts enabled
MISC_CONTROL_BITS, 0x0404, // DAC:SR1 selected,ADC:SR0 selected
VENDOR_ID_1, 0x4144, // Read-only string
VENDOR_ID_2, 0x5360 // Read-only string
};
/** external functions **/
/** external data **/
/** internal functions **/
/** public data **/
UINT gDataBufferHead;
UINT gDataBufferTail;
UCHAR gDataBuffer[MAX_DATA_BUFFER_SIZE];
/** private data **/
static USHORT *gpRxBuffer;
static USHORT *gpTxBuffer;
static USHORT gCodecInitResults[CODEC_REG_INIT_LENGTH];
static UINT gCurrentAC97State;
static UINT gInterruptCount;
static USHORT gTxBuffer[FRAME_BUFFER_LEN >> 1];
static USHORT gRxBuffer[FRAME_BUFFER_LEN >> 1];
/** public functions **/
/** private functions **/
static void CodecReset (void);
static void InitSPORT0 (void);
static void InitSPORT0DMA (void *pTxBuffer, void *pRxBuffer);
static void InitCodec (void);
EX_INTERRUPT_HANDLER (AC97_ISR);
bool AC97_Init (void)
{
UINT chipVer;
gCurrentAC97State = AC97_STATE_UNDEFINED;
gInterruptCount = 0;
gDataBufferHead = gDataBufferTail = 0;
memset (&gDataBuffer, 0, sizeof (gDataBuffer));
gpRxBuffer = &gRxBuffer[0];//AllocDMABlock (FRAME_BUFFER_LEN);
gpTxBuffer = &gTxBuffer[0];//AllocDMABlock (FRAME_BUFFER_LEN);
if ((gpRxBuffer == nil) || (gpTxBuffer == nil))
return( false);
//Initialize the Tx Buffer with defaults
memset (gpTxBuffer, 0, FRAME_BUFFER_LEN);
gpTxBuffer[oTagPhase >> 1] = kVldFrm|kVldCmd|kVldAddr;
gpTxBuffer[oCmdAddrSlot >> 1] = SERIAL_CONFIGURATION;
gpTxBuffer[oCmdDataSlot >> 1] = 0x9900;
CodecReset ();
InitSPORT0 ();
InitSPORT0DMA (gpTxBuffer, gpRxBuffer);
// install the interrupt handler
//register_handler(ik_ivg8, AC97_ISR);
register_handler(ik_ivg7, AC97_ISR);
chipVer = 0xf0000000 & chipId_REG;
if(chipVer)
{
// rev. 1.0 or higher
SIC_IMASK_REG |= SIC_MASK4; //SPORT0 RX DMA
}
else
{
// rev. 0.x
SIC_IMASK_REG &= ~(SIC_MASK4);
}
asm("ssync;");
//IMASK_REG |= 0x0100; // unmask IVG 8 at core
IMASK_REG |= 0x0080; // unmask IVG 7 at core
asm("ssync;");
gCurrentAC97State = AC97_STATE_INITIALIZING_CODEC_STARTED;
InitCodec ();
gCurrentAC97State = AC97_STATE_INITIALIZING_CODEC_COMPLETED;;
return (true);
}
/*------------------------------------------------------------
* EnablePlayback
*
* Parameters:
*
* Globals Used:
* None
*
* Description:
* Enable playback on the codec.
*
* Returns:
*
*
*------------------------------------------------------------*/
void AC97_EnablePlayback (void)
{
gpTxBuffer[oLeft >> 1] = 0;
gpTxBuffer[oRght >> 1] = 0;
gpTxBuffer[oTagPhase >> 1] = kVldFrm | kVldLeft | kVldRight;
gCurrentAC97State = AC97_STATE_PLAY_DATA;
}
/*------------------------------------------------------------
* EnablePlayback
*
* Parameters:
*
* Globals Used:
* None
*
* Description:
* Disable playback on the codec.
*
* Returns:
*
*
*------------------------------------------------------------*/
void AC97_DisablePlayback (void)
{
gCurrentAC97State = AC97_STATE_INITIALIZING_CODEC_COMPLETED;
gpTxBuffer[oLeft >> 1] = 0;
gpTxBuffer[oRght >> 1] = 0;
gpTxBuffer[oLeft >> 1] = 0;
gpTxBuffer[oRght >> 1] = 0;
}
/*------------------------------------------------------------
* AC97_SetVolumeAndMute
*
* Parameters:
*
* Globals Used:
* None
*
* Description:
* This routine sets the line-out volume and mute!
*
* Returns:
*
*
*------------------------------------------------------------*/
void AC97_SetVolumeAndMute (USHORT leftVol, USHORT rightVol, UCHAR mute)
{
UCHAR leftVolB;
UCHAR rightVolB;
USHORT regData;
UINT interruptCount;
if (leftVol != 0)
leftVolB = (UCHAR)(((~(USHORT)leftVol) & 0xffff) / (USHORT)0x180);
else
leftVolB = 0;
if (rightVol != 0)
rightVolB = (UCHAR)(((~(USHORT)rightVol) & 0xffff) / (USHORT)0x180);
else
rightVolB = 0;
regData = ((mute == 0) ? 0x0000 : 0x8000) | (((USHORT)leftVolB & 0x3f) << 8) | rightVolB & 0x3f;
Dprintf2 ("l: %4x, r: %4x", leftVol, rightVol);
Dprintf1 ("RegData: %4x", regData);
gpTxBuffer[oCmdAddrSlot >> 1] = MASTER_VOLUME;
gpTxBuffer[oCmdDataSlot >> 1] = regData;
//Now it's safe to say we've got address and data
gpTxBuffer[oTagPhase >> 1] |= (kVldCmd|kVldAddr); //we've got commands coming in
//Wait for atleast two SPORT interrupt
interruptCount = gInterruptCount;
while (interruptCount == gInterruptCount)
asm ("nop;");
//Wait for atleast two SPORT interrupt
interruptCount = gInterruptCount;
while (interruptCount == gInterruptCount)
asm ("nop;");
//Now it's safe to say we've got address and data
gpTxBuffer[oTagPhase >> 1] &= ((USHORT)~(kVldCmd|kVldAddr)); //we've removed the commands now!
}
/*------------------------------------------------------------
* CodecReset
*
* Parameters:
*
* Globals Used:
* None
*
* Description:
* This routine resets the codec.
*
* Returns:
*
*
*------------------------------------------------------------*/
void CodecReset (void)
{
UINT countdown;
FIO_DIR_REG = kLEDSet + kACResSet; // set output pins
asm("ssync;");
FIO_FLAG_S_REG = kLEDSet + kACResSet; // turn LEDs on,AC not yet in reset
asm("ssync;");
countdown = TC_1MS_300MHZ;
while (countdown)
countdown--;
FIO_FLAG_C_REG = kLEDSet+kACResSet; // assert AD1885 /RESET (active low)
asm("ssync;");
//hold reset
// AD1885 /Reset Active low for ca
// 2 usec (needs 1 us)
// assuming 300 Mhz DSP Core
countdown = TC_2US_300MHZ;
while (countdown)
countdown--;
FIO_FLAG_S_REG = kLEDMix+kACResSet; // De-assert AD1885 /RESET and turn on
// (~)half of the LEDs
asm("ssync;");
// use another 3 seconds to allow codec to recover from reset
// 162.8 ns needed before outputting BITCLK according to datasheet??
countdown = TC_3S_300MHZ;
while (countdown)
countdown--;
FIO_FLAG_S_REG = kLEDSet + kACResSet; // turn LEDs on
asm("ssync;");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -