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

📄 codeccontrol.cpp

📁 NXP LPC3000系列 wince BSP包
💻 CPP
📖 第 1 页 / 共 2 页
字号:

#include "wavemain.h"
#include "uda1380.h"
#include "bsp.h"

// IMPORTANT NOTE
// When programming the CODEC, the WS clock should be running to generate
// the base clock fo the CODEC WSPLL. Failure to run the WS clock will
// cause some CODEC operations to fail!

// Static driver data
int CODECControl::m_codecinstances              = 0;
DWORD CODECControl::m_codecgoodinit             = 0;
HANDLE CODECControl::m_codecdrvI2CCtl           = INVALID_HANDLE_VALUE;
UINT32 CODECControl::m_codecsavedVol            = 0xFFFFFFFF;
DWORD CODECControl::m_codecboostEnable          = 0;
UINT32 CODECControl::m_codecSavedBoostLevel     = 0;
DWORD CODECControl::m_codecmuteEnabled          = 0;
DWORD CODECControl::m_codecHeadPhoneEnabledFlag = 1;
DWORD CODECControl::m_codecLineInUsedFlag       = 1;
UINT32 CODECControl::m_codecGainADCPGA          = 0;
UINT16 CODECControl::m_codecGainADCVGA          = 0;
UINT32 CODECControl::m_codecVolDecimator        = 0;
DWORD CODECControl::m_codecDigitalMixerEnabled  = 1;

//********************************************************************
// Initial setup data for the I2S device (via I2C)
//********************************************************************
typedef struct
{
	UNS_8 reg;
	UNS_16 val;
} I2S_SETUP_T;
static I2S_SETUP_T i2sinitdata[] =
{
	// L3 reset
	{UDA1380_REG_L3,          0x0000},
	// CODEC ADC and DAC clock from WSPLL, all clocks enabled
	{UDA1380_REG_EVALCLK,     0x0F30},
	// I2S bus data I/O formats, use digital mixer for output
	// BCKO is slave
	{UDA1380_REG_I2S,         0x0000},
	// Enable all power for now
	{UDA1380_REG_PWRCTRL,     0xA5D0},
	// Full mixer analog input gain
	{UDA1380_REG_ANAMIX,      0x0000},
	// Enable headphone short circuit protection
	{UDA1380_REG_HEADAMP,     0x0202},
	// Full master volume
	{UDA1380_REG_MSTRVOL,     0x0000},
	// Enable full mixer volume on both channels
	{UDA1380_REG_MIXVOL,      0x0000},
	// Bass and treble boost set to flat
	{UDA1380_REG_MODEBBT,     0x0000},
	// Disable mute and de-emphasis
	{UDA1380_REG_MSTRMUTE,    0x0000},
	// Mixer off, other settings off
	{UDA1380_REG_MIXSDO,      0x0000},
	// ADC decimator volume to max
	{UDA1380_REG_DECVOL,      0x0000},
	// No PGA mute, full gain
	{UDA1380_REG_PGA,         0x0F0F},
	// Select line in and MIC, max MIC gain
	{UDA1380_REG_ADC,         0x0F02},
	// AGC
	{UDA1380_REG_AGC,         0x0000},
	// End of list
	{0xFF,                    0xFFFF}
};

//********************************************************************
// Initialization and de-init functions
//********************************************************************

// Constructor
CODECControl::CODECControl(void)
{
	// Assume output channel until changed
	m_codecchanDir = I2S_OUT_CH;

	m_codecinstances++;
	if (m_codecinstances == 1)
	{	
		m_codecgoodinit = 1;

		// Open I2C driver to communicate with I2S
		m_codecdrvI2CCtl = CreateFile(I2SI2SDEVNAME, (GENERIC_READ | GENERIC_WRITE),
			(FILE_SHARE_WRITE | FILE_SHARE_READ), NULL, OPEN_EXISTING,
			FILE_ATTRIBUTE_SYSTEM, 0);
		if (m_codecdrvI2CCtl == INVALID_HANDLE_VALUE)
		{
			RETAILMSG(1,
			    (TEXT("CODECContext: Error initializing I2C CODEC interface\r\n")));
			m_codecgoodinit = 0;
		}

		// Set static default levels for all instances
		m_codecsavedVol             = 0xFFFFFFFF;
		m_codecboostEnable          = 1;
		m_codecSavedBoostLevel      = 0;
		m_codecmuteEnabled          = 1;
		m_codecHeadPhoneEnabledFlag = 1;
		m_codecLineInUsedFlag       = 1;
		m_codecGainADCPGA           = 0;
		m_codecGainADCVGA           = 0;
		m_codecVolDecimator         = 0;
		m_codecDigitalMixerEnabled  = 1;
	}
}

// Destructor
CODECControl::~CODECControl(void)
{
	m_codecinstances--;
	if (m_codecinstances == 0)
	{
		// Delete I2C driver instance
		if (m_codecdrvI2CCtl != INVALID_HANDLE_VALUE)
		{
			CloseHandle(m_codecdrvI2CCtl);
			m_codecdrvI2CCtl = INVALID_HANDLE_VALUE;
		}

		m_codecgoodinit = 0;
	}
}

// Returns initialized 'good' status after construction
DWORD CODECControl::codecIsInitGood(void)
{
	return m_codecgoodinit;
}

// Setup CODEC default registers, this should be done once the I2S
// clock is running
DWORD CODECControl::codecSetup(void)
{
	int idx;
	DWORD goodSetup = 1;

	// Initialize CODEC via I2C interface
	idx = 0;
	while (i2sinitdata[idx].reg != 0xFF)
	{
		if (codecWriteReg(i2sinitdata[idx].val, i2sinitdata[idx].reg) == 0)
		{
			goodSetup = 0;
		}

		idx++;
	}

	return goodSetup;
}

// Set direction for this instances
void CODECControl::codecSetDirection(I2S_CH_T ch)
{
	m_codecchanDir = ch;
}

//********************************************************************
// CODEC raw register read/write functions
//********************************************************************

// Write a value to a CODEC register
DWORD CODECControl::codecWriteReg(UINT16 val,
							      UINT8 reg)
{
	DWORD good;
	I2C_OUT_XFER_T xferout;
	I2C_IN_XFER_T xferin;

	// Setup transfer
	xferout.flags_buff [0] = (I2S_DEV_ADDR | I2C_WRITE | I2C_START_FLAG);
	xferout.flags_buff [1] = reg;

	// Start read operation with repeated start
	xferout.flags_buff [2] = ((val >> 8) & 0xFF);
	xferout.flags_buff [3] = (((val >> 0) & 0xFF) | I2C_STOP_FLAG);

	// Send 4 bytes, read 0 bytes
	xferout.tosend = 4;
	xferout.torecv = 0;

	good = codecI2CTransaction(&xferout, &xferin);
	if (good != 0)
	{
		if (xferin.ist != I2CST_COMPLETE)
		{
			good = 0;
		}
	}

	return good;
}

// Read a value from a register
DWORD CODECControl::codecReadReg(UINT16 *val,
							     UINT8 reg)
{
	DWORD good;
	I2C_OUT_XFER_T xferout;
	I2C_IN_XFER_T xferin;

	// Setup transfer
	xferout.flags_buff [0] = (I2S_DEV_ADDR | I2C_WRITE | I2C_START_FLAG);
	xferout.flags_buff [1] = reg;

	// Start read operation with repeated start
	xferout.flags_buff [2] = (I2S_DEV_ADDR | I2C_READ | I2C_START_FLAG);

	// Read 2 bytes, send 3 bytes
	xferout.tosend = 3;
	xferout.torecv = 2;

	good = codecI2CTransaction(&xferout, &xferin);
	if (good != 0)
	{
		if (xferin.ist != I2CST_COMPLETE)
		{
			good = 0;
		}
		else
		{
			*val = ((UINT16) xferin.buff[0] << 8) |
				((UINT16) xferin.buff[1]);
		}
	}

	return good;
}

//********************************************************************
// CODEC clock and power control functions
//********************************************************************

// Adjust the CODEC PLL to the pass sample rate
DWORD CODECControl::codecSetPLLRate(DWORD wsrate)
{
	UINT16 rmask, regval;
	DWORD setGood = 0;

	// Based on the WS rate, the PLL also needs to be adjusted
	if (wsrate < 12500)
	{
		rmask = EVALCLK_WSPLL_SEL6_12K;
	}
	else if (wsrate < 25000)
	{
		rmask = EVALCLK_WSPLL_SEL12_25K;
	}
	else if (wsrate < 50000)
	{
		rmask = EVALCLK_WSPLL_SEL25_50K;
	}
	else
	{
		rmask = EVALCLK_WSPLL_SEL50_100K;
	}

	// Read current value first
	if (codecReadReg(&regval, UDA1380_REG_EVALCLK) != 0)
	{
		regval = regval & ~0x3;
		regval = regval | rmask;
		if (codecWriteReg(regval, UDA1380_REG_EVALCLK) != 0)
		{
			setGood = 1;
		}
	}

	return setGood;
}

// Power down/up the output or input side of the CODEC. This will enable
// power in the CODEC for output or input functionality. This should only
// be used when bringing up or down the CODEC
DWORD CODECControl::codecPowerUp(DWORD powerup)
{
	// TBD fix me
	// Not support yet, CODEC is always powered on
	return 1;
}

// Returns power up status for input or output channels
DWORD CODECControl::codecIsPoweredUp(void)
{
	// TBD fix me
	// Not support yet, CODEC is always powered on
	return 1;
}

// Enable clocking for the output or input side of the CODEC. This can
// be used to gate clocking when no audio is output or input to save
// power.
DWORD CODECControl::codecClockUp(DWORD clockup)
{
	// TBD fix me
	// Not support yet, CODEC is always clocked
	return 1;
}

// Returns clocking status for input or output channels
DWORD CODECControl::codecIsClockUp(void)
{
	// TBD fix me
	// Not support yet, CODEC is always clocked
	return 1;
}

//********************************************************************
// Sound control functions
//********************************************************************

// Return or set volume, accepts and returns a value beween 0 and 0xFFFF,
// 0 will mute the volume, High 16 bits=right, low 16 bits=left
DWORD CODECControl::codecSetMasterVolume(UINT32 newvol)
{
	UINT16 trunVolL, trunVolR, vol;
	DWORD status = 0;

	// Skip if no changes are needed
	if (m_codecsavedVol == newvol)
	{
		return 1;
	}

	trunVolL = 0xFFFF - (UINT16) ((newvol >> 0) & 0xFFFF);
	trunVolR = 0xFFFF - (UINT16) ((newvol >> 16) & 0xFFFF);

	// The I2S CODEC uses 8 bits for volume level for each channel (left
	// and right), so use just the upper 8 bits for the left and right
	// channels
	vol = ((trunVolL >> 8) & 0x00FF) | ((trunVolR >> 0) & 0xFF00);

	// Write to the volume register
	if (codecWriteReg(vol, UDA1380_REG_MSTRVOL) != 0)
	{
		status = 1;
		m_codecsavedVol = newvol;
	}

	return status;
}

// Return current master volume, High 16 bits=right, low 16 bits=left
UINT32 CODECControl::codecGetMasterVolume(void)
{
	return m_codecsavedVol;
}

// Bass and treble boost enable/disable
DWORD CODECControl::codecEnableBoost(DWORD enable)
{
	UINT16 regval;
	DWORD good = 0;

	// Skip if no changes are needed
	if (m_codecboostEnable == enable)
	{
		return 1;
	}

	// Read current value first
	if (codecReadReg(&regval, UDA1380_REG_MODEBBT) != 0)
	{
		if (enable != 0)
		{
			regval |= MODEBBT_BOOST_MASK;
		}
		else
		{
			regval &= ~MODEBBT_BOOST_MASK;
		}
		if (codecWriteReg(regval, UDA1380_REG_MODEBBT) != 0)
		{
			good = 1;
			m_codecboostEnable = enable;
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -