📄 audioctl.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
// Portions Copyright (c) Texas Instruments. All rights reserved.
//
//------------------------------------------------------------------------------
//
// EAC controller platform specific configuration.
//
// Most settings depend on the codec, modem and bluetooth chip connected to
// the OMAP2420 chipset.
//
#include <wavemain.h>
#include <omap3_defs.h>
#include <ceddk.h>
#include <spi.h>
#include <tsc2101.h>
#include "xhwctxt.h"
//------------------------------------------------------------------------------
// Globals
const GUID DEVICE_IFC_CLK_GUID;
const GUID DEVICE_IFC_SPI_GUID;
//------------------------------------------------------------------------------
//
// platform specific definition for codec port
//
// on P2 Sample platform the codec port is configured as I2S
//
//------------------------------------------------------------------------------
//
// EAC BT auSPI pin muxing defines and function.
//
#define MODE1_INTERNAL_BTAUSPI_SOURCE_BITS (BIT3|BIT2) // Bits used to select BT EAC AuSPI source
#define MODE1_V3U3V2T4_AS_BTAUSPI_SOURCE (BIT2) // use pins V3/U3/V2/T4 as source
#define MODE1_W6R9Y6Y5_AS_BTAUSPI_SOURCE 0 // use pins W6/R9/Y6/Y5 as source
// TSC2101 constants
#define TSC2101_PAGE2 0x1000
//------------------------------------------------------------------------------
//
// TSC2101Write - uses SPI to write a value to one of the TSC2101 registers
//
static void TSC2101Write(HANDLE hSPI, WORD wReg, WORD wData)
{
DWORD dwCommand;
dwCommand = ((DWORD)(TSC2101_PAGE2 | wReg) << 16) | wData;
SPITransfer(hSPI, &dwCommand);
}
//------------------------------------------------------------------------------
//
// TSC2101Read - uses SPI to read a value from one of the TSC2101 registers
//
static WORD TSC2101Read(HANDLE hSPI, WORD wReg)
{
DWORD dwCommand;
dwCommand = (DWORD)(TSC2101_READ | TSC2101_PAGE2 | wReg) << 16;
SPITransfer(hSPI, &dwCommand);
return (WORD)dwCommand;
}
//------------------------------------------------------------------------------
//
// test code to generate a tone without DMA
//
//#define TEST_TONE
#if defined(TEST_TONE)
#define TEST_SOUND awSound // awTone (below) or awSound (from sound.h)
#define TEST_READ_COUNT 44100
#if (TEST_SOUND == awSound)
#define TEST_WRITE_COUNT 1
#else
#define TEST_WRITE_COUNT 1000
#endif
#include "sound.h" // awSound array
WORD awInput[TEST_READ_COUNT];
WORD awTone[] =
{
0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
};
static BOOL McBSPRead(OMAP2420_McBSP_REGS *pMcBSP, PWORD pwData)
{
WORD wReg, wAttempts;
*pwData = INREG16(&pMcBSP->usMCBSP_DRR1);
wReg = INREG16(&pMcBSP->usMCBSP_SPCR1);
if (wReg & MCBSP_RSYNCERR)
{
OUTREG16(&pMcBSP->usMCBSP_SPCR1, wReg & (~MCBSP_RSYNCERR));
DEBUGMSG(ZONE_AC, (L"AC: McBSPRead FAILED on RSYNC\r\n"));
}
else
{
for (wAttempts = 0; wAttempts < 1000; wAttempts++)
{
wReg = INREG16(&pMcBSP->usMCBSP_SPCR1);
if (wReg & MCBSP_RRDY)
{
return TRUE;
}
}
OUTREG16(&pMcBSP->usMCBSP_SPCR1, wReg & (~MCBSP_RRST));
Sleep(1);
OUTREG16(&pMcBSP->usMCBSP_SPCR1, wReg | MCBSP_RRST);
Sleep(1);
DEBUGMSG(ZONE_AC, (L"AC: McBSPRead FAILED on RRDY\r\n"));
}
return FALSE;
}
static BOOL McBSPWrite(OMAP2420_McBSP_REGS *pMcBSP, WORD wData)
{
WORD wReg, wAttempts;
OUTREG16(&pMcBSP->usMCBSP_DXR1, wData);
wReg = INREG16(&pMcBSP->usMCBSP_SPCR2);
if (wReg & MCBSP_XSYNCERR)
{
OUTREG16(&pMcBSP->usMCBSP_SPCR2, wReg & (~MCBSP_XSYNCERR));
DEBUGMSG(ZONE_AC, (L"AC: McBSPWrite FAILED on XSYNC\r\n"));
}
else
{
for (wAttempts = 0; wAttempts < 1000; wAttempts++)
{
wReg = INREG16(&pMcBSP->usMCBSP_SPCR2);
if (wReg & MCBSP_XRDY)
{
return TRUE;
}
}
OUTREG16(&pMcBSP->usMCBSP_SPCR2, wReg & (~MCBSP_XRST));
Sleep(1);
OUTREG16(&pMcBSP->usMCBSP_SPCR2, wReg | MCBSP_XRST);
Sleep(1);
DEBUGMSG(ZONE_AC, (L"AC: McBSPWrite FAILED on XRDY\r\n"));
}
return FALSE;
}
static void TestTone(OMAP2420_McBSP_REGS *pMcBSP)
{
DWORD i, j;
DEBUGMSG(ZONE_AC, (L"AC: +TestTone\r\n"));
Sleep(10);
// write the test data
for (i = 0; i < TEST_WRITE_COUNT; i++)
{
for (j = 0; j < sizeof(TEST_SOUND) / sizeof(WORD); j++)
{
if (!McBSPWrite(pMcBSP, TEST_SOUND[j]))
{
DEBUGMSG(ZONE_AC, (L"AC: -TestTone write %u %u\r\n", i, j));
return;
}
}
}
// read some input data
DEBUGMSG(ZONE_AC, (L"AC: start recording\r\n"));
for (i = 0; i < TEST_READ_COUNT; i++)
{
if (!McBSPRead(pMcBSP, awInput + i))
{
DEBUGMSG(ZONE_AC, (L"AC: -TestTone read %u\r\n", i));
return;
}
}
DEBUGMSG(ZONE_AC, (L"AC: stop recording\r\n"));
for (i = 0; i < TEST_READ_COUNT; i++)
{
if (!(i & 0xF))
{
DEBUGMSG(ZONE_AC, (L"\r\n\t"));
}
DEBUGMSG(ZONE_AC, (L"%04X, ", awInput[i]));
}
// write back what was read
for (i = 0; i < TEST_READ_COUNT; i++)
{
if (!McBSPWrite(pMcBSP, awInput[i]))
{
DEBUGMSG(ZONE_AC, (L"AC: -TestTone writeback %u\r\n", i));
return;
}
}
Sleep(10);
DEBUGMSG(ZONE_AC, (L"AC: -TestTone\r\n"));
}
#endif // TEST_TONE
//------------------------------------------------------------------------------
//
// Function: HardwareContext::CreateHWContext
//
// This function creates a hardware context using a platform specific derived
// class based on HardwareContext. In order to support different hardware
// configurations in one binary the approbriate class could be created here.
//
//
BOOL HardwareContext::CreateHWContext(DWORD Index)
{
if (g_pHWContext)
{
return TRUE;
}
g_pHWContext = new ACAudioHWContext((LPTSTR)Index);
if (!g_pHWContext)
{
return FALSE;
}
return g_pHWContext->Init(Index);
}
//------------------------------------------------------------------------------
//
// Function: HWMapControllerRegs()
//
// map hardware registers to device driver virtual addresses
//
BOOL
ACAudioHWContext::HWMapControllerRegs()
{
PHYSICAL_ADDRESS pa;
DEBUGMSG(ZONE_AC, (L"+ACAudioHWContext::HWMapControllerRegs()\r\n"));
// set the power state
if (!m_hParent)
{
DEBUGMSG(ZONE_ERROR, (L"ACAudioHWContext::HWMapControllerRegs: "
L"ERROR setting the power state.\r\n"
));
goto ErrExit;
}
m_CurPowerState = D2;
SetDevicePowerState(m_hParent, D2 , NULL);
// get the McBSP pointer
pa.HighPart= 0;
pa.LowPart = AUDIO_MCBSP_REGS_PA;
m_pMCBSPRegisters = (OMAP2420_McBSP_REGS *)MmMapIoSpace(pa, N1KB, FALSE);
if (!m_pMCBSPRegisters)
{
DEBUGMSG(ZONE_ERROR, (L"ACAudioHWContext::HWMapControllerRegs: "
L"ERROR mapping MCBSP registers.\r\n"
));
goto ErrExit;
}
// get the PRCM registers pointer
pa.LowPart = OMAP2420_PRCM_REGS_PA;
m_pPRCMRegs = (OMAP2420_PRCM_REGS *)MmMapIoSpace(pa, sizeof(OMAP2420_PRCM_REGS), FALSE);
if (!m_pPRCMRegs)
{
DEBUGMSG(ZONE_ERROR, (L"ACAudioHWContext::HWMapControllerRegs: "
L"Allocating PRCM register failed.\r\n"
));
goto ErrExit;
}
// open the SPI device
m_hSPI = SPIOpen();
if (!m_hSPI)
{
DEBUGMSG(ZONE_ERROR, (L"ACAudioHWContext::HWMapControllerRegs: "
L"Failed to open the SPI device driver.\r\n"
));
goto ErrExit;
}
// configure the SPI device
if (!SPISetSlaveAddress(m_hSPI, 0))
{
DEBUGMSG(ZONE_ERROR, (L"ACAudioHWContext::HWMapControllerRegs: "
L"Failed to set the SPI slave address.\r\n"
));
goto ErrExit;
}
return TRUE;
ErrExit:
// reset all mappings in case of error
m_pMCBSPRegisters = NULL;
m_pPRCMRegs = NULL;
m_hSPI = NULL;
return FALSE;
}
//------------------------------------------------------------------------------
//
// Function: SetCodecPower
//
// Set CODEC port power state.
//
VOID
ACAudioHWContext::SetCodecPower(BOOL fPowerOn)
{
DEBUGMSG(ZONE_AC, (L"+ACAudioHWContext::SetCodecPower(%x)\r\n", fPowerOn));
// power on or off the BSP and CODEC
if (fPowerOn)
{
CLRREG16(&m_pMCBSPRegisters->usMCBSP_PCR, MCBSP_IDLEEN);
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_POWER, CPC_SP1PWDN | CPC_SP2PWDN);
}
else
{
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_POWER, CPC_MBIAS_HND | CPC_MBIAS_HED | CPC_ASTPWD |
CPC_SP1PWDN | CPC_SP2PWDN | CPC_DAPWDN | CPC_ADPWDN | CPC_VGPWDN |
CPC_COPWDN | CPC_LSPWDN);
SETREG16(&m_pMCBSPRegisters->usMCBSP_PCR, MCBSP_IDLEEN);
}
}
//------------------------------------------------------------------------------
//
// Function: InitCodecPort()
//
// Configures the codec port.
//
void
ACAudioHWContext::InitCodecPort()
{
UINT16 uiTmp;
DEBUGMSG(ZONE_AC, (L"+ACAudioHWContext::InitCodecPort()\r\n"));
// power down everything
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_POWER, CPC_MBIAS_HND | CPC_MBIAS_HED | CPC_ASTPWD |
CPC_SP1PWDN | CPC_SP2PWDN | CPC_DAPWDN | CPC_ADPWDN | CPC_VGPWDN |
CPC_COPWDN | CPC_LSPWDN);
// headset input not muted, AGC for Headset In off
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_HEADSET, HGC_ADPGA_HED(0x7F));
// handset input not muted, AGC for Handset In off
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_HANDSET, HNGC_ADPGA_HND(0x7F));
// mute analog sidetone, select MIC_INHED input for headset
// Cell Phone In not connected
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_MIXER, MPC_ASTMU | MPC_ASTG(0x600) | MPC_MICADC |
MPC_MICSEL(1));
// ADC, DAC, Analog Sidetone, cellphone, buzzer
// softstepping enabled, 1dB AGC hysteresis, MICes bias 2V
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_4, AC4_MB_HED(0));
// Set codec output volume
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_DAC, DGC_DALVL(0) | DGC_DARVL(0));
// DAC left and right routed to SPK2, SPK1/2 unmuted
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_5, AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 | AC5_HDSCPTC);
// OUT8P/N muted, CPOUT muted
// TSC2101Write(m_hSPI, TSC2101_AUDCTRL_6, AC6_MUTSPK2 |
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_6, AC6_MUTSPK2 | AC6_SPL2LSK | AC6_AST2LSK |
AC6_LDSCPTC | AC6_VGNDSCPTC);
// Headset/Hook switch detect disabled
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_7, 0);
// set I2S, word length, and reference sampling rate (RFS) divisor
if (BITSPERSAMPLE == 20) uiTmp = 1;
else if (BITSPERSAMPLE == 24) uiTmp = 2;
else if (BITSPERSAMPLE == 32) uiTmp = 3;
else uiTmp = 0;
TSC2101Write(m_hSPI, TSC2101_AUDCTRL_1, AC1_WLEN(uiTmp) | AC1_DACFS(0) | AC1_ADCFS(0));
// make the TSC2101 the master vs. the McBSP, set the RFS to 44100 or 48000
uiTmp = AC3_SLVMS | ((SAMPLERATE == 44100) ? AC3_REFFS : 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -