📄 wmxscaleaclink.c
字号:
if ( !private_IsCodecReady( hDevice ) )
{
WM_TRACE( hDevice, ( "WMPlatformACLinkColdReset: Codec ready bit not set" ));
status = WMS_CODEC_NOT_READY;
goto error;
}
#endif /* WM_USE_XLLP_AC97 */
return WMS_SUCCESS;
error:
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMPlatformACLinkWarmReset
*
* Forces a warm reset of the WM97xx device, waking it up again but leaving it
* in its previous state (with all the register settings as they were before
* the sleep).
*
* Note: we assume the workaround is in place for the XScale bug, and hence
* this function can operate normally - the cold reset line is not connected
* to our chip so we won't see it go low.
*
* See WMPlatformConfig.h for more details.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
WMSTATUS WMPlatformACLinkWarmReset( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
WMSTATUS status;
WM_BOOL codecReady;
/*
* If we've got codec ready, we're already awake.
*/
if ( private_IsCodecReady( hDevice ) )
{
goto done;
}
/* Do the warm reset */
pDeviceContext->v_pAC97Regs->GCR |= AC97GCR_WarmReset;
/*
* The XScale will have gone into cold reset as a result of the warm reset
* bug. Take it out of cold reset to persuade it to continue.
*
* Note: we can only get away with this because the reset line isn't
* connected.
*/
pDeviceContext->v_pAC97Regs->GCR |= AC97GCR_ColdReset;
/*
* A warm reset typically takes around 1.3 microseconds.
* A full frame takes approx 20.83us. It takes us somewhere between
* one and two frames (depending on how the timing hits) to get codec
* ready to the CPU. Unfortunately, it then takes the PXA2xx ages to
* notice that codec ready is set... 500us seems to work reliably.
*/
MicroSleep( pDeviceContext, 500 );
/* Check for codec ready. */
codecReady = private_IsCodecReady( hDevice );
if ( !codecReady )
{
WM_TRACE( hDevice, ( "WMPlatformACLinkWarmReset: Codec ready bit not set" ));
#if WM_DEBUG_CHECK_CODEC_READY
WM_ASSERT( hDevice, codecReady );
#endif /* WM_DEBUG_CHECK_CODEC_READY */
status = WMS_CODEC_NOT_READY;
goto error;
}
done:
return WMS_SUCCESS;
error:
return status;
}
/*-----------------------------------------------------------------------------
* Function: private_WaitForCommandDone (static)
*
* Waits for the Command Done bit in the status register. This bit is set
* once the AC Controller has received the command address and data.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
static WMSTATUS private_WaitForCommandDone( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
WMSTATUS status;
unsigned long timeout = 0;
while( !( pDeviceContext->v_pAC97Regs->GSR & AC97GSR_CDONE ) )
{
if ( ++timeout > CODEC_TIMEOUT )
{
status = WMS_DEVICE_BUSY;
goto error;
}
/* Allow other threads to continue if we can */
WMBeNice( hDevice );
};
return WMS_SUCCESS;
error:
return status;
}
/*-----------------------------------------------------------------------------
* Function: private_WaitForStatusDone (static)
*
* Waits for the Status Done bit in the status register. This bit is set
* once the AC Controller has received the status address and data.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
static WMSTATUS private_WaitForStatusDone( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
WMSTATUS status;
unsigned long timeout = 0;
while( !( pDeviceContext->v_pAC97Regs->GSR & AC97GSR_SDONE ) )
{
if ( ++timeout > CODEC_TIMEOUT )
{
status = WMS_DEVICE_BUSY;
goto error;
}
/* Allow other threads to continue if we can */
WMBeNice( hDevice );
};
return WMS_SUCCESS;
error:
return status;
}
/*-----------------------------------------------------------------------------
* Function: private_ConfigureACLinkGPIO
*
* This function configures the GPIO pins for the AC link on the Lubbock
* platform, as follows:
*
* Signals Pin# Direction Alternate Function
* SYNC GPIO31 output 2
* SDATA_OUT GPIO30 output 2
* BIT_CLK GPIO28 input 1
* SDATA_IN_0 GPIO29 input 1
* (SDATA_IN_1 GPIO32 input 1)
*
* On the Mainstone platform the SYSCLK is generated by the Bulverde processor
*
* Signals Pin# Direction Alternate Function
* SYSCLK GPIO45 output 1
* (SDATA_IN_1 GPIO99 input 2)
*
* Note: SDATA_IN_1 is treated slightly oddly. Slots 2-12 are multiplexed to
* SDATA_IN_0, and hence you cannot have data on the same slot on SDATA_IN_0
* and SDATA_IN_1 in the same frame, although you can have data on different
* slots - e.g. if you have one codec for audio (slots 3 & 4) and one as a
* modem (slot 5). Slot 1 is obviously read from both to determine which line
* to latch the data in from for that frame.
*
* This has the effect that codec ready appears on GSR bit 8 (PCR) for the
* codec attached to SDATA_IN_0, and on GSR bit 9 (SCR) for the codec attached
* to SDATA_IN_1. For everything else the two codecs lines are effectively
* identical - SDATA_OUT goes to both, and the address (primary or secondary)
* determines which codec picks it up (they'd better not be both primary!).
*
* The net effect of this is (for Wolfson devices) that regardless of which
* location the device is connected to, all operation is identical except the
* codec ready bit.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
static WMSTATUS private_ConfigureACLinkGPIO( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
WMSTATUS status;
WM_ASSERT( hDevice, NULL != pDeviceContext->v_pWMData );
WM_ASSERT( hDevice, NULL != pDeviceContext->v_pGPIORegs );
/* Only need to do this once */
if ( pDeviceContext->v_pWMData )
{
if ( pDeviceContext->v_pWMData->flags & WM_GPIO_CONFIGURED_AC97 )
{
goto done;
}
}
/*
* Check to see if a different control interface has already
* been initialised by another driver.
* If it has been we should not try to configure this interface.
*/
if ( pDeviceContext->v_pWMData->flags & WM_GPIO_CONFIGURED_I2S )
{
status = WMS_RESOURCE_CONFLICT;
goto error;
}
WM_ASSERT( hDevice, NULL != pDeviceContext->v_pGPIORegs );
/* SDATAOUT and SYNC are outputs (1) */
pDeviceContext->v_pGPIORegs->GPIO_REG(GPDR) |=
GPIO_BIT_SDATA_OUT | GPIO_BIT_SYNC;
/* BITCLK and SDATA_IN0 are inputs (0) */
pDeviceContext->v_pGPIORegs->GPIO_REG(GPDR) &=
~(GPIO_BIT_BITCLK | GPIO_BIT_SDATA_IN_0);
/* So is SDATA_IN1 - but it's a different GPIO bank, just to be awkward */
//pDeviceContext->v_pGPIORegs->GPIO_REG_SDATA_IN_1(GPDR) &=
// ~GPIO_BIT_SDATA_IN_1;
/* Set up the correct alternate functions */
pDeviceContext->v_pGPIORegs->GPIO_ALTFN_REG =
(pDeviceContext->v_pGPIORegs->GPIO_ALTFN_REG & ~GPIO_ALTFN_MASK)|
GPIO_ALTFN_AC97_BITCLK |
GPIO_ALTFN_AC97_SDATA_IN_0 |
GPIO_ALTFN_AC97_SDATA_OUT |
GPIO_ALTFN_AC97_SYNC;
//pDeviceContext->v_pGPIORegs->GPIO_ALTFN_REG_SDATA_IN_1 =
// (pDeviceContext->v_pGPIORegs->GPIO_ALTFN_REG_SDATA_IN_1 & ~GPIO_ALTFN_MASK_SDATA_IN_1)
// | GPIO_ALTFN_AC97_SDATA_IN_1;
/*
* Note: although we set up the SDATA_IN1 GPIO, the rest of the code just
* relies on the multiplexing.
*/
/*
* Set up our GPIO as an alternate reset line to work
* around the bug in the XScale (see WMPlatformConfig.h for
* more details).
*/
/* It's an output */
pDeviceContext->v_pGPIORegs->RESET_GPIO_REG(GPDR) |= RESET_GPIO_MASK;
/* Select the correct alternate function */
pDeviceContext->v_pGPIORegs->RESET_GPIO_ALTFN_REG =
(pDeviceContext->v_pGPIORegs->RESET_GPIO_ALTFN_REG & ~RESET_GPIO_ALTFN_MASK)
| RESET_GPIO_ALTFN;
#if WM_BOARD_MAINSTONEII
/* SYSCLK is an output (1) */
pDeviceContext->v_pGPIORegs->GPIO_REG_AC97_SYSCLK(GPDR) |= GPIO_BIT_AC97_SYSCLK;
pDeviceContext->v_pGPIORegs->GPIO_ALTFN_REG_AC97_SYSCLK =
(pDeviceContext->v_pGPIORegs->GPIO_ALTFN_REG_AC97_SYSCLK & ~GPIO_ALTFN_MASK_AC97_SYSCLK)
| GPIO_ALTFN_AC97_SYSCLK;
#endif /* WM_BOARD_MAINSTONEII */
/*
* And we're done.
*/
done:
/* Remember it's done so we don't try to do it twice */
if ( pDeviceContext->v_pWMData )
{
pDeviceContext->v_pWMData->flags |= ( WM_GPIO_CONFIGURED_AC97 |
WM_GPIO_CONFIGURED_HIFI
);
}
return WMS_SUCCESS;
error:
return status;
}
/*-----------------------------------------------------------------------------
* Function: private_UnconfigureACLinkGPIO
*
* This function configures the GPIO pins for the AC link on the Lubbock
* platform, as follows:
*
* Signals Pin# Direction Alternate Function
* SYNC GP31 output 2
* SDATA_OUT GP30 output 2
* BIT_CLK GP28 input 1
* SDATA_IN_0 GP29 input 1
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: void
*---------------------------------------------------------------------------*/
static void private_UnconfigureACLinkGPIO( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
/* We're less configured now */
if ( pDeviceContext->v_pWMData )
{
pDeviceContext->v_pWMData->flags &= ~( WM_GPIO_CONFIGURED_HIFI |
WM_GPIO_CONFIGURED_AC97
);
}
return;
}
#endif /* WM_AC97 */
/*------------------------------ END OF FILE ---------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -