📄 xllp_ac97.c
字号:
do
{
gotLink = XllpAc97LinkLock(pAc97Reg);
if (XLLP_FALSE == gotLink) // 1 usec is a long time. Skip delay if possible.
{
XllpOstDelayMicroSeconds(pOstRegs, 1);
}
} // Wait while time remaining and ACLINK not available
while (timeRemaining-- && (XLLP_FALSE == gotLink));
if (XLLP_FALSE == gotLink) // Didn't get the ACLINK
{
status = XLLP_AC97_LINK_LOCK_FAIL;
}
else // We got the link. Perform the write operation and don't wait.
{
// First, clear old write status indication CDONE by writing a ONE to that bit.
pAc97Reg->GSR = XLLP_AC97_GSR_CDONE_MSK;
*pCodecReg = data; // Now the write!
// Wait until write cycle is complete. There should be a way
// to do this speculatively at the beginning of the procedure.
// Need to discover it. Too inefficient to always wait.
timeRemaining = maxRWTimeOutUs;
do
{
XllpOstDelayMicroSeconds(pOstRegs, 1);
} // Wait while time remaining and command I/O still incomplete.
while ( (timeRemaining--) && !(pAc97Reg->GSR & XLLP_AC97_GSR_CDONE_MSK));
if (!(pAc97Reg->GSR & XLLP_AC97_GSR_CDONE_MSK))
status = XLLP_AC97_CODEC_ACCESS_TIMEOUT;
} // Got AC link
done:
return(status);
} // Ac97CtrlCodecWrite()
/*******************************************************************************
*
* FUNCTION: XllpAc97Read
*
* DESCRIPTION: Read the value of a specific mixer register in a specified
* AC'97 codec or modem, using the AC Link.
*
* INPUT PARAMETERS:
* XLLP_UINT16_T offset : the offset address of the codec register to read.
* XLLP_UINT16_T pData : the pointer to where will hold the read result.
* P_XLLP_AC97_T pAc97Reg : a pointer to AC97 unit registers structure.
* XLLP_UINT32_T maxRWTimeOutUs : timeout value in the reading process.
* XLLP_AC97_CODEC_SEL_T codecSel : specify which codec device to read.
*
* RETURNS:
* Success: 0 (XLLP_AC97_NO_ERROR)
* Failure: XLLP_AC97_LINK_LOCK_FAIL: AC Link was not available within the
* timeout interval.
* XLLP_AC97_CODEC_ACCESS_TIMEOUT: Reading was not finished within the
* timeout interval.
*
*
* CALLS: XllpAc97LinkLock, XllpOstDelayMicroSeconds
*
* CALLED BY:
*
* PROTOTYPE: XLLP_AC97_ERROR_T XllpAc97Read(XLLP_UINT16_T offset,
* XLLP_UINT16_T *pdata,
* P_XLLP_AC97_T pAc97Reg,
* P_XLLP_OST_T pOstRegs,
* XLLP_UINT32_T maxRWTimeOutUs,
* XLLP_AC97_CODEC_SEL_T codecSel);
*
*******************************************************************************/
XLLP_AC97_ERROR_T XllpAc97Read(XLLP_UINT16_T offset,
XLLP_UINT16_T *pdata,
P_XLLP_AC97_T pAc97Reg,
P_XLLP_OST_T pOstRegs,
XLLP_UINT32_T maxRWTimeOutUs,
XLLP_AC97_CODEC_SEL_T codecSel)
{
XLLP_AC97_ERROR_T status = XLLP_AC97_NO_ERROR;
XLLP_BOOL_T gotLink;
XLLP_UINT32_T timeRemaining;
P_XLLP_VUINT32_T pCodecReg;
// Point to specified register within area mapped to target codec regs
// Check for special case register 54h the GPIO status register
#ifdef WM9712
if(offset == XLLP_AC97_CR_E_MDM_GPIO_PIN_STAT)
{
// Select the Primary or Secondary modem IO address space
if (XLLP_AC97_CODEC_PRIMARY == codecSel)
pCodecReg = &(pAc97Reg->CodecRegsPrimaryMdm[0]);
else
pCodecReg = &(pAc97Reg->CodecRegsSecondaryMdm[0]);
pCodecReg += offset / XLLP_AC97_CODEC_REGS_PER_WORD;
// The data is received on Slot 12 and stored by the
// ACUNIT so we can read back straight away.
*pdata = (XLLP_UINT16_T)(*pCodecReg);
goto done;
}
else
{
// Select the Primary or Secondary Audio IO address space
if (XLLP_AC97_CODEC_PRIMARY == codecSel)
pCodecReg = &(pAc97Reg->CodecRegsPrimaryAud[0]);
else
pCodecReg = &(pAc97Reg->CodecRegsSecondaryAud[0]);
pCodecReg += offset / XLLP_AC97_CODEC_REGS_PER_WORD;
}
#else
// Select the Primary or Secondary Audio IO address space
if (XLLP_AC97_CODEC_PRIMARY == codecSel)
pCodecReg = &(pAc97Reg->CodecRegsPrimaryAud[0]);
else
pCodecReg = &(pAc97Reg->CodecRegsSecondaryAud[0]);
pCodecReg += offset / XLLP_AC97_CODEC_REGS_PER_WORD;
#endif
//Lock the ACLINK
timeRemaining = XLLP_AC97_LOCK_TIMEOUT_DEF;
do
{
gotLink = XllpAc97LinkLock(pAc97Reg);
if (XLLP_FALSE == gotLink) // 1 usec is a long time. Skip delay if possible.
{
XllpOstDelayMicroSeconds(pOstRegs, 1);
}
} // Wait while time remaining and ACLINK not available
while (timeRemaining-- && (XLLP_FALSE == gotLink));
if (XLLP_FALSE == gotLink) // Didn't get the ACLINK
{
status = XLLP_AC97_LINK_LOCK_FAIL;
}
else // We got the link. Perform the write operation and don't wait.
{
// First, clear old read status indications.
pAc97Reg->GSR = XLLP_AC97_GSR_SDONE_MSK | XLLP_AC97_GSR_RCS_ERR_MSK;
*pdata = (XLLP_UINT16_T)(*pCodecReg); // This is THE DUMMY READ.
// Wait for read I/O with codec to complete before doing real read.
timeRemaining = maxRWTimeOutUs;
do
{
XllpOstDelayMicroSeconds(pOstRegs, 1);
} // Wait while time remaining and read I/O still incomplete
while( (timeRemaining--) && (!(pAc97Reg->GSR & XLLP_AC97_GSR_SDONE_MSK)) );
if ((pAc97Reg->GSR & XLLP_AC97_GSR_SDONE_MSK) && (!(pAc97Reg->GSR & XLLP_AC97_GSR_RCS_ERR_MSK)) )
{
// succeed in reading. clear status bits first.
pAc97Reg->GSR = XLLP_AC97_GSR_SDONE_MSK | XLLP_AC97_GSR_RCS_ERR_MSK;
*pdata = (XLLP_UINT16_T)(*pCodecReg); // THE REAL READ.
timeRemaining = maxRWTimeOutUs;
do
{
XllpOstDelayMicroSeconds(pOstRegs, 1);
} // Wait while time remaining and read I/O still incomplete
while( (timeRemaining--) && (!(pAc97Reg->GSR & XLLP_AC97_GSR_SDONE_MSK)) );
}
else // failed
{
status = XLLP_AC97_CODEC_ACCESS_TIMEOUT;
pAc97Reg->CAR = XLLP_AC97_CAR_CAIP_CLEAR;
} // else (OK to do real read)
} // else (We got the link. Perform the read operations.)
return (status);
} // XllpAc97Read ()
/*******************************************************************************
*
* FUNCTION: XllpAc97ColdReset
*
* DESCRIPTION: After a cold reset of the processor's AC'97 Controller,
* check the AC Link and all AC'97 codecs and modems attached to
* the controller's AC'97 cold reset pin.
*
* INPUT PARAMETERS:
* pAc97ctxt a pointer to a XLLP_AC97_CONTEXT_T struct, which contains
* necessary information.
*
* RETURNS:
* Success: 0 (XLLP_AC97_NO_ERROR)
* Failure: XLLP_AC97_CODEC_NOT_READY: A timeout occurred on one of the codecs.
* In systems with multiple codecs, the calling function
* could determine which device(s) is/are not ready by
* performing XllpAc97GetStatus() on
* AC97CTRL_STAT_PCRDY and AC97CTRL_STAT_SCRDY.
*
* GLOBAL EFFECTS: All codecs initialized to default settings. Controller
* set to default state and is operational.
*
* ASSUMPTIONS: Not used in an interrupt service routine.
*
* CALLS: XllpOstDelayMicroSeconds
*
* CALLED BY: XllpAc97Init
*
* PROTOTYPE: XLLP_AC97_ERROR_T XllpAc97ColdReset(P_XLLP_AC97_CONTEXT_T pAc97ctxt);
*
*******************************************************************************/
XLLP_AC97_ERROR_T XllpAc97ColdReset(P_XLLP_AC97_CONTEXT_T pAc97ctxt)
{
XLLP_AC97_ERROR_T status = XLLP_AC97_NO_ERROR;
P_XLLP_AC97_T pAC97 = pAc97ctxt->pAc97Reg;
P_XLLP_OST_T pOstRegs = pAc97ctxt->pOstRegs;
XLLP_BOOL_T priCodecReady, secCodecReady;
XLLP_UINT32_T timeRemaining;
pAC97->GCR = 0;
// Hold reset active for a minimum time
XllpOstDelayMicroSeconds(pOstRegs, XLLP_AC97_COLD_HOLDTIME);
// Deactivate cold reset condition
pAC97->GCR |= XLLP_AC97_GCR_COLD_RESET_MSK;
// Set nReset high. This is a workaround for some strange behavior of nReset pin.
{
XLLP_UINT32_T pins[6];
pins[0] = 1;
pins[1] = 113;
XllpGpioSetOutputState1(pAc97ctxt->pGpioReg, pins);
}
// And wait with timeout for all codecs to respond.
priCodecReady = XLLP_FALSE;
if (XLLP_FALSE == pAc97ctxt->useSecondaryCodec)
{
secCodecReady = XLLP_TRUE;
}
else
{
secCodecReady = XLLP_FALSE;
}
timeRemaining = pAc97ctxt->maxSetupTimeOutUs;
do
{
XllpOstDelayMicroSeconds(pOstRegs, 1);
if (pAC97->GSR & XLLP_AC97_GSR_PCRDY_MSK)
priCodecReady = XLLP_TRUE;
if (pAC97->GSR & XLLP_AC97_GSR_SCRDY_MSK)
secCodecReady = XLLP_TRUE;
}
while (timeRemaining-- && ((priCodecReady == XLLP_FALSE) || (secCodecReady == XLLP_FALSE)));
// Timeout status if some of the devices weren't ready.
if ((priCodecReady == XLLP_FALSE) || (secCodecReady == XLLP_FALSE))
{
status = XLLP_AC97_CODEC_NOT_READY;
}
return (status);
} // XllpAc97ColdReset ()
/*******************************************************************************
*
* FUNCTION: XllpAc97ShutdownAcLink
*
* DESCRIPTION: Try to shutdown the AC Link by setting the corresponding bit
* in GCR of AC97 unit.
*
* INPUT PARAMETERS: None
* P_XLLP_AC97_T pAc97Reg : a pointer to AC97 unit registers structure.
*
* RETURNS:
* Success: 0 (XLLP_AC97_NO_ERROR)
* Failure: XLLP_AC97_LINK_SHUTDOWN_FAIL: A timeout occurred in shutdown process.
*
* CALLS: XllpOstDelayMicroSeconds
*
* CALLED BY: XllpAc97DeInit
*
* PROTOTYPE: XLLP_AC97_ERROR_T XllpAc97ShutdownAclink(P_XLLP_AC97_T pAc97Reg,
* P_XLLP_OST_T pOstRegs);
*
*******************************************************************************/
XLLP_AC97_ERROR_T XllpAc97ShutdownAclink(P_XLLP_AC97_T pAc97Reg, P_XLLP_OST_T pOstRegs)
{
XLLP_AC97_ERROR_T status = XLLP_AC97_NO_ERROR;
XLLP_UINT32_T timeRemaining = XLLP_AC97_LINKOFF_TIMEOUT_DEF;
pAc97Reg->GCR |= XLLP_AC97_GCR_LINK_OFF_MSK;
while (!(pAc97Reg->GSR & XLLP_AC97_GSR_ACOFFD_MSK))
{
timeRemaining --;
if (0 == timeRemaining)
{
status = XLLP_AC97_LINK_SHUTDOWN_FAIL;
break;
}
XllpOstDelayMicroSeconds(pOstRegs, 1);
}
return(status);
}
/*******************************************************************************
*
* FUNCTION: XllpAc97LinkLock
*
* DESCRIPTION: Try to lock the AC Link for command/status accesses to a
* codec.
*
* INPUT PARAMETERS:
* P_XLLP_AC97_T pAc97Reg : a pointer to AC97 unit registers structure.
*
* RETURNS: XLLP_TRUE if the attempt was successful; XLLP_FALSE if not.
*
* GLOBAL EFFECTS: If true, the hardware indicator will show that the AC Link
* is locked until either a codec command or status I/O
* operation has completed, or Ac97CtrlReleaseAcLink
* is called.
*
* CALLS:
*
* CALLED BY: XllpAc97Write, XllpAc97Read
*
* PROTOTYPE: XLLP_BOOL_T XllpAc97LinkLock(P_XLLP_AC97_T pAc97Reg);
*
*******************************************************************************/
XLLP_BOOL_T XllpAc97LinkLock(P_XLLP_AC97_T pAc97Reg)
{
XLLP_BOOL_T status = XLLP_TRUE;
XLLP_VUINT32_T carTmp;
carTmp = pAc97Reg->CAR;
if (carTmp & XLLP_AC97_CAR_CAIP_MSK) // "1" in CAIP bit means lock failed.
{
status = XLLP_FALSE;
}
return (status);
} // XllpAc97LinkLock()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -