📄 wmcontrollink.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: WMControlLink.c 4253 2006-10-24 15:36:43Z ian $
*
* This file encapsulates the control operations required by drivers for Wolfson
* chips.
*
* Warning:
* This driver is specifically written for Wolfson Codecs. It is not a
* general CODEC device driver.
*
* -----------------------------------------------------------------------------*/
/*
* Include files
*/
#include "WMCommon.h"
#include "WMDevice.h"
#include "WMGlobals.h"
#include "WMControlLink.h"
#if WM_TESTING
# include "Test/WMTestCommon.h"
# include "Test/WMLinkTests.h"
# include "Test/WMGPIOTests.h"
#endif
/*
* Global definitions
*/
/*
* Convert between registers and array indices.
*/
#define REG_TO_INDEX( _reg ) ( (_reg) >> 1 )
#define INDEX_TO_REG( _index ) ( (_index) << 1 )
/*
* Shorthand for whether to do register operation tracing.
*/
#if WM_DEBUG_TRACE_REGISTERS
# define WM_REG_TRACE WM_TRACE
#else
# define WM_REG_TRACE( _hDevice, _args ) (0)
#endif /* WM_DEBUG_TRACE_REGISTERS */
/*
* There are two sets of code for handling volume registers with BOTH bits
* (which update both registers with a single write).
*
* - Generic code which checks through all signals on the device to find
* other signals which match, and updates those.
* - Quick and dirty code which hard-codes for the WM8731 family, but
* has a simple switch statement.
*
* If WM_BOTH_QUICK_AND_DIRTY is set to TRUE (the default), the quicker but
* WM8731-family-specific code is built. If set to FALSE, the generic code
* is built.
*/
#define WM_BOTH_QUICK_AND_DIRTY TRUE
/*
* Private data
*/
/*
* Function prototypes
*/
WMSTATUS WMPlatformLinkInit( WM_DEVICE_HANDLE hDevice,
WM_DRIVER_ID driverId
);
void WMPlatformLinkShutdown( WM_DEVICE_HANDLE hDevice,
WM_DRIVER_ID driverId
);
WMSTATUS WMPlatformRead( WM_DEVICE_HANDLE hDevice,
WM_REGTYPE reg,
WM_REGVAL *pValue
);
WMSTATUS WMPlatformWrite( WM_DEVICE_HANDLE hDevice,
WM_REGTYPE reg,
WM_REGVAL value
);
WMSTATUS WMPlatformInitDeviceId( WM_DEVICE_HANDLE hDevice );
WMSTATUS WMPlatformReset( WM_DEVICE_HANDLE hDevice );
WMSTATUS WMPlatformWake( WM_DEVICE_HANDLE hDevice );
static WM_BOOL private_IsValidRegister( WM_DEVICE_HANDLE hDevice,
WM_REGTYPE reg
);
static void private_ResetState( WM_DEVICE_HANDLE hDevice );
#if WM_USE_SHADOW_REGISTERS
static WMSTATUS private_InitShadowRegisters( WM_DEVICE_HANDLE hDevice );
static WMSTATUS private_WriteShadowRegister( WM_DEVICE_HANDLE hDevice,
WM_REGTYPE reg,
WM_REGVAL value
);
static WMSTATUS private_ReadShadowRegister( WM_DEVICE_HANDLE hDevice,
WM_REGTYPE reg,
WM_REGVAL *pValue
);
static WMSTATUS private_ReadDefaultShadowRegister( WM_DEVICE_HANDLE hDevice,
WM_REGTYPE reg,
WM_REGVAL *pValue
);
#endif /* WM_USE_SHADOW_REGISTERS */
/*-----------------------------------------------------------------------------
* Function: WMLinkInit
*
* Initialises the use of the control link by a given driver.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* driverId The driver ID (e.g. WM_DRIVER_AUDIO)
*
* Returns: WMSTATUS
* See WMStatus.h.
*---------------------------------------------------------------------------*/
WMSTATUS WMLinkInit( WM_DEVICE_HANDLE hDevice, WM_DRIVER_ID driverId )
{
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
WMSTATUS status;
WM_CHIPTYPE chipType;
WM_CHIPREV chipRev;
unsigned int driver = DRIVER_TO_INDEX( driverId );
WM_ASSERT( hDevice, driver < WM_MAX_DRIVERS );
/*
* Check to make sure this is a valid driverId
*/
if ( driver > WM_MAX_DRIVERS )
{
status = WMS_INVALID_PARAMETER;
goto error0;
}
/*
* Lock our global data.
*/
if ( !WMLockGlobalData( hDevice ) )
{
status = WMS_LOCK_TIMED_OUT;
goto error0;
}
/*
* Let the platform layer do its stuff.
*/
if ( !(pDeviceContext->flags & DEVICE_INITIALISED ) )
{
#if WM_CACHE_POWER_STATE
/*
* If it's I2S we've automatically got a link, and we need it
* for our initialisation.
*/
if ( pDeviceContext->v_pWMData &&
WM_IS_I2S_DEVICE_ID( pDeviceContext->deviceID )
)
{
pDeviceContext->v_pWMData->WmPower |= WM_POWER_LINK;
}
#endif
WM_TRACE( hDevice, ( "=======================================================" ) );
WM_TRACE( hDevice,
( "=== Wolfson Device Control Library version %s ===",
WM_VERSION_STRING
)
);
WM_TRACE( hDevice, ( "=======================================================" ) );
#if WM_USE_SHADOW_REGISTERS
/*
* Note: Read-Only devices have to initialise the shadow registers
* _before_ initialising the link.
*/
if ( pDeviceContext->v_pWMData &&
!WM_DEVICE_HAS_READBACK( pDeviceContext->deviceID )
)
{
/*
* If this is the first driver to be then we need to
* initialise our shadow registers. Assume it's at its default
* values, and hope no-one else is writing to it
* directly before we get a chance.
*/
if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
{
/*
* Set our shadow registers to their default values.
*/
status = private_InitShadowRegisters( hDevice );
if ( WM_ERROR( status ) )
{
goto error0;
}
}
}
#endif
status = WMPlatformLinkInit( hDevice, driverId );
if ( WM_ERROR( status ) &&
! ( WM_IS_GENERIC_FAMILY( hDevice ) && WMS_UNSUPPORTED == status ) )
{
goto error1;
}
}
/*
* The link should now be running.
*/
#if WM_CACHE_POWER_STATE
if ( pDeviceContext->v_pWMData )
{
pDeviceContext->v_pWMData->WmPower |= WM_POWER_LINK;
}
#endif
/*
* Check what we are.
*/
status = WMGetDeviceType( hDevice, &chipType, &chipRev );
if ( WM_ERROR( status ) )
{
goto error2;
}
/*
* And tell the user.
*/
WM_TRACE( hDevice, ( "Using Wolfson device %s rev %c",
WM_CHIP_STRING( chipType ),
( WM_REV_UNKNOWN == chipRev ) ? '?' : chipRev
));
/*
* Now do initialisation which relies on the shared memory area.
*/
if ( pDeviceContext->v_pWMData )
{
#if WM_USE_SHADOW_REGISTERS
/*
* Note: Read-Write devices have to initialise the shadow registers
* _after_ initialising the link and getting the Device Type.
*/
if ( WM_DEVICE_HAS_READBACK( pDeviceContext->deviceID ) )
{
/*
* If this is the first driver to be then we need to
* initialise our shadow registers. Assume it's at its default
* values, and hope no-one else is writing to it
* directly before we get a chance.
*/
if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
{
/*
* Set our shadow registers to their default values.
*/
status = private_InitShadowRegisters( hDevice );
if ( WM_ERROR( status ) )
{
goto error0;
}
}
}
#endif
/*
* If this is the first driver to be then we need to
* initialise our state. Assume it's at its default
* values, and hope no-one else is writing to it
* directly before we get a chance.
*/
if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
{
private_ResetState( hDevice );
#if WM_CACHE_POWER_STATE
/* Note: the link should be running now. */
pDeviceContext->v_pWMData->WmPower |= WM_POWER_LINK;
#endif /* WM_CACHE_POWER_STATE */
}
/*
* We've got another driver.
*/
if ( !(pDeviceContext->v_pWMData->activeDrivers & WM_DRIVER_MASK( driver ) ) )
{
pDeviceContext->v_pWMData->activeDrivers |= WM_DRIVER_MASK( driver );
#if WM_CACHE_POWER_STATE
pDeviceContext->v_pWMData->powerRequirements[driver] = 0;
#endif
}
}
/*
* We've got another driver.
*/
pDeviceContext->activeDrivers |= WM_DRIVER_MASK( driver );
/* Let other threads in again */
WMUnlockGlobalData( hDevice );
/*
* Do some sanity tests if we've been asked to.
*/
#if WM_TESTING
# if WM_AUTOTEST_BASIC
WMTEST_RUN( WMTestLink( hDevice ) );
# endif
# if WM_GPIO_CONTROL
# if WM_AUTOTEST_GPIO_CONTROL_BASIC
WMTEST_RUN( WMTestGPIOBasic( hDevice ) );
# endif
# if WM_AUTOTEST_GPIO_CONTROL_ADVANCED
WMTEST_RUN( WMTestGPIOAdvanced( hDevice ) );
# endif
# endif /* WM_GPIO_CONTROL */
#endif /* WM_TESTING */
/*
* We're done.
*/
return status;
/*
* Error cleanup.
*/
error2:
WMLinkShutdown( hDevice, driverId );
error1:
WMUnlockGlobalData( hDevice );
error0:
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMLinkShutdown
*
* Marks the end of use of the control link by this driver.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* driverId The driver ID (e.g. WM_DRIVER_AUDIO)
*
* Returns: void
*---------------------------------------------------------------------------*/
void WMLinkShutdown( WM_DEVICE_HANDLE hDevice, WM_DRIVER_ID driverId )
{
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
unsigned int driver = DRIVER_TO_INDEX( driverId );
WM_ASSERT( hDevice, driver < WM_MAX_DRIVERS );
/*
* Lock our global data.
*/
if ( !WMLockGlobalData( hDevice ) )
{
goto done;
}
/*
* There's one fewer driver.
*/
if ( pDeviceContext->v_pWMData )
{
if ( pDeviceContext->v_pWMData->activeDrivers & WM_DRIVER_MASK( driver ) )
{
pDeviceContext->v_pWMData->activeDrivers &= ~WM_DRIVER_MASK( driver );
/*
* Global cleanup if this is the last driver to leave.
*/
if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
{
WMPlatformLinkShutdown( hDevice, driverId );
}
}
}
pDeviceContext->activeDrivers &= ~WM_DRIVER_MASK( driver );
/* Let other threads in again */
WMUnlockGlobalData( hDevice );
done:
return;
}
/*-----------------------------------------------------------------------------
* Function: WMRead
*
* Reads the value from the given register.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* reg register to read from
* pValue variable to receive value
*
* Returns: WMSTATUS
* See WMStatus.h.
*---------------------------------------------------------------------------*/
WMSTATUS WMRead( WM_DEVICE_HANDLE hDevice,
WM_REGTYPE reg,
WM_REGVAL *pValue
)
{
WMSTATUS status = WMS_SUCCESS;
WMSTATUS platformStatus;
WM_REGVAL value = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -