⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 codec.c

📁 windows ce 下ARM9音频驱动代码
💻 C
📖 第 1 页 / 共 2 页
字号:


/*++
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 + -