📄 wmxscaleaclink.c
字号:
/*-----------------------------------------------------------------------------
* Copyright (c) Wolfson Microelectronics plc. All rights reserved.
*
* This software as well as any related documentation is furnished under
* license and may only be used or copied in accordance with the terms of the
* license. The information in this file is furnished for informational use
* only, is subject to change without notice, and should not be construed as
* a commitment by Wolfson Microelectronics plc. Wolfson Microelectronics plc
* assumes no responsibility or liability for any errors or inaccuracies that
* may appear in this document or any software that may be provided in
* association with this document.
*
* Except as permitted by such license, no part of this document may be
* reproduced, stored in a retrieval system, or transmitted in any form or by
* any means without the express written consent of Wolfson Microelectronics plc.
*
* $Id: WMXScaleACLink.c 2924 2006-04-12 12:50:25Z fb $
*
* This file contains XScale AC Link functionality for the drivers for
* the Wolfson chips.
*
* Warning:
* This driver is specifically written for Wolfson Codecs. It is not a
* general CODEC device driver.
*
* This platform file is specifically designed to work with the Cotulla AC'97
* controller and the Lubbock and Mainstone XScale platforms from Intel. There
* is no guarantee of correct operation with other platforms/controllers.
*
* -----------------------------------------------------------------------------*/
/*
* IMPORTANT
*
* The functions in this file must obey two rules:
*
* 1. They do not use any memory other than stack space and parameters passed in.
* 2. They do not make system calls, unless the context parameter
* preventSyscallCount is zero.
*
* All functions take a context parameter, which passes in pointers to the virtual
* addresses of memory-mapped registers, and stores what type of device is being
* accessed.
*
* Some client functions provide shared memory via the v_pWMData member of the
* context structure. This cannot be relied on.
*/
/*
* Note: In some circumstances, checking the CAIP bit in the CAR can cause
* Bulverde (PXA270) to hang. This means that these raw functions are not
* synchronised across threads/processes, and hence the higher level functions
* are responsible for ensuring this synchronisation.
*/
/*
* Include files
*/
#include "WMCommon.h"
#include "WMPlatformACLink.h"
#include "WMInterrupts.h"
#include "WMDevice.h"
#include "WMPlatformDeviceContext.h"
#include "Test/WMTestCommon.h"
#include "Test/WMInternalTests.h"
#if WM_USE_XLLP_AC97
# include "xllp_acodec.h"
# include "xllp_ac97acodec.h"
#endif /* WM_USE_XLLP_AC97 */
#if WM_BOARD_MAINSTONEII
# include "xllp_bcr.h"
#endif /* WM_BOARD_MAINSTONEII */
#if WM_AC97
/*
* Global definitions
*/
/*
* Access to the register spaces.
*/
#define PRIMARY_CODEC_REGS(_ctx) ((unsigned int)&_ctx->v_pAC97Regs->CodecRegsPrimaryAud)
#if XLLP_AVAILABLE
#define SECONDARY_CODEC_REGS(_ctx) ((unsigned int)&_ctx->v_pAC97Regs->CodecRegsSecondaryAud)
#define PRIMARY_MODEM_REGS(_ctx) ((unsigned int)&_ctx->v_pAC97Regs->CodecRegsPrimaryMdm)
#define SECONDARY_MODEM_REGS(_ctx) ((unsigned int)&_ctx->v_pAC97Regs->CodecRegsSecondaryMdm)
#else /* XLLP_AVAILABLE */
#define SECONDARY_CODEC_REGS(_ctx) ((unsigned int)&_ctx->v_pAC97Regs->CodecRegsPrimaryAud + 0x100)
#define PRIMARY_MODEM_REGS(_ctx) ((unsigned int)&_ctx->v_pAC97Regs->CodecRegsPrimaryAud + 0x200)
#define SECONDARY_MODEM_REGS(_ctx) ((unsigned int)&_ctx->v_pAC97Regs->CodecRegsPrimaryAud + 0x300)
#endif /* XLLP_AVAILABLE */
/*
* Build up an ACodec context structure from our pDeviceContext.
*/
#define ACODEC_FROM_DEVICE_CONTEXT( pACodecIn, pDeviceContext ) do { \
XLLP_ACODEC_CONTEXT_T *pACodec = pACodecIn; \
switch ( pDeviceContext->deviceType ) \
{ \
case WM_CHIP_WM9703: \
pACodec->ACodecId = WM_9703_ID; \
break; \
case WM_CHIP_WM9704: \
pACodec->ACodecId = WM_9704_ID; \
break; \
case WM_CHIP_WM9705: \
pACodec->ACodecId = WM_9705_ID; \
break; \
case WM_CHIP_WM9712: \
pACodec->ACodecId = WM_9712_ID; \
break; \
case WM_CHIP_WM9713: \
pACodec->ACodecId = WM_9713_ID; \
break; \
default: \
pACodec->ACodecId = 0; \
} \
pACodec->pGpioReg = pDeviceContext->v_pGPIORegs; \
pACodec->pPCMReg = (XLLP_I2S_T *) pDeviceContext->v_pAC97Regs; \
pACodec->pCtrlReg = NULL; \
pACodec->pClockReg = pDeviceContext->v_pClkRegs; \
pACodec->pSSPReg = NULL; \
pACodec->pOSTRegs = (XLLP_OST_T *) pDeviceContext->v_pOSTimerRegs; \
pACodec->uMaxReadWriteTimeOutMs = CODEC_TIMEOUT; \
pACodec->uMaxSetupTimeOutMs = CODEC_TIMEOUT; \
\
if ( WM_DEV_AC97_PRIMARY == pDeviceContext->deviceID ) \
pACodec->bUseSecondaryCodec = 0; \
else \
pACodec->bUseSecondaryCodec = 1; \
} while (0)
/*
* Function prototypes
*/
/*-----------------------------------------------------------------------------
* Macro: private_IsCodecReady
*
* Detects whether the codec is ready to rumble - whether the appropriate
* codec ready bit is set.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: WM_BOOL
* TRUE if the codec is ready.
*---------------------------------------------------------------------------*/
#define private_IsCodecReady( pDeviceContext ) \
((((WM_XSCALE_DEVICE_CONTEXT *)pDeviceContext)->v_pAC97Regs->GSR & AC97GSR_CODEC_READY)\
? TRUE : FALSE )
/*
* Private data
*/
/*
* Function prototypes
*/
static WMSTATUS private_WaitForCommandDone( WM_DEVICE_HANDLE hDevice );
static WMSTATUS private_WaitForStatusDone( WM_DEVICE_HANDLE hDevice );
static WMSTATUS private_ConfigureACLinkGPIO( WM_DEVICE_HANDLE hDevice );
static void private_UnconfigureACLinkGPIO( WM_DEVICE_HANDLE hDevice );
/*-----------------------------------------------------------------------------
* Function: WMPlatformACLinkInit
*
* Initialises the WM97xx platform-specific layer for the specific hardware
* and leaves it with the AC-Link up and running.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
WMSTATUS WMPlatformACLinkInit( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
WMSTATUS status;
/*
* Multiple drivers may try to initialise the codec. We need to
* check with the codec to see if it is already initialised.
* If we can succesfully check to see if the codec ready bit is set
* then the device has already been initialised.
* This also stops the code from trying to perform a cold or warm
* reset when the link is running which is a good side effect.
*/
if ( private_IsCodecReady( hDevice ) )
{
goto done;
}
if ( ! pDeviceContext->v_pWMData->powerStateFlags & WM_ASLEEP )
{
/*
* Check our internals code, if
* this is _not_ WakeUp form SLEEP/IDLE
*/
WMTEST_RUN( WMTestPlatformInternals( hDevice ) );
}
/*
* If we're using XLLP, let it take care of the details.
*/
#if WM_USE_XLLP_AC97
{
XLLP_ACODEC_CONTEXT_T ACodecCtxStruct;
XLLP_ACODEC_ERROR_T xllpStatus;
ACODEC_FROM_DEVICE_CONTEXT( &ACodecCtxStruct, pDeviceContext );
#if !WM_MULTIPLE_CHIP_SUPPORT && WM9713_FAMILY
/*
* The WM9713 has specific requirements so we should tell XLLP
* as soon as possible.
*/
ACodecCtxStruct.ACodecId = WM_9713_ID;
#else /* !WM_MULTIPLE_CHIP_SUPPORT && WM9713_FAMILY */
/*
* Take a guess for now which will tell XLLP it's one of our
* AC97 codecs - we'll check later exactly which one.
*/
ACodecCtxStruct.ACodecId = WM_9712_ID;
#endif /* ! WM_MULTIPLE_CHIP_SUPPORT && WM9713_FAMILY*/
/*
* And call through to XLLP to do the work for us.
*/
xllpStatus = XllpACodecInit( &ACodecCtxStruct );
if ( XLLP_ACODEC_SUCCESS != xllpStatus )
{
WM_TRACE( hDevice, (
"XllpACodecInit failed: 0x%X", xllpStatus ));
status = XllpStatusToWMStatus( xllpStatus );
goto error;
}
#if WM_MULTIPLE_CHIP_SUPPORT && WM9713_FAMILY
status = WMGetDeviceType(hDevice, NULL, NULL);
if ( WM_ERROR(status) )
{
WM_TRACE( hDevice, ( "WMGetDeviceType failed: %s",
WMStatusText( status ) ) );
goto error;
}
if ( IS_WM9713_FAMILY( hDevice ) )
{
/*
* The WM9713 has specific requirements so we should tell XLLP
* as soon as possible.
*/
ACodecCtxStruct.ACodecId = WM_9713_ID;
/*
* And call through to XLLP to do the work for us (again).
*/
xllpStatus = XllpACodecInit( &ACodecCtxStruct );
if ( XLLP_ACODEC_SUCCESS != xllpStatus )
{
WM_TRACE( hDevice, ( "XllpACodecInit failed: 0x%X", xllpStatus ));
status = XllpStatusToWMStatus( xllpStatus );
goto error;
}
}
#endif /* WM_MULTIPLE_CHIP_SUPPORT && WM9713_FAMILY */
}
#else /* WM_USE_XLLP_AC97 */
/*
* No XLLP - we need to do it all ourselves.
*/
/*
* Set up the GPIOs.
*/
status = private_ConfigureACLinkGPIO( hDevice );
if ( WM_ERROR( status ) )
{
goto error;
}
/*
* Make sure the clock's running.
*/
pDeviceContext->v_pClkRegs->cken |= XLLP_CLKEN_AC97;
/* Wake up the AC Link */
status = WMPlatformACLinkColdReset( hDevice );
if ( WM_ERROR( status ) )
{
goto error;
}
/* Check for the codec ready bit */
if ( !private_IsCodecReady( hDevice ) )
{
WM_TRACE( hDevice, ( "WMPlatformACLinkInit: Codec ready bit not set" ));
status = WMS_CODEC_NOT_READY;
goto error;
}
#endif /* WM_USE_XLLP_AC97 */
#ifdef DEBUG
if ( pDeviceContext->v_pAC97Regs->GSR & AC97GSR_CODEC0_READY )
{
WM_TRACE( hDevice, ( "WM97: Codec on SDATA_IN_0" ));
}
if ( pDeviceContext->v_pAC97Regs->GSR & AC97GSR_CODEC1_READY )
{
WM_TRACE( hDevice, ( "WM97: Codec on SDATA_IN_1" ));
}
#endif /* DEBUG */
/*
* It worked.
*/
done:
pDeviceContext->flags |= DEVICE_INITIALISED;
return WMS_SUCCESS;
error:
WMPlatformACLinkShutdown( hDevice );
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMPlatformACLinkShutdown
*
* Shuts down the WM97xx platform-specific layer.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: void
*---------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -