📄 wm97power.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: WM97Power.c 2828 2006-04-06 14:11:45Z ian $
*
* This file contains functionality for controlling power on AC97 codecs.
*
* 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 "WMControlLink.h"
#include "WMPlatformACLink.h"
#include "WMACLink.h"
#include "WMPower.h"
#include "WM97Power.h"
/*
* Global definitions
*/
/*
* Touch panel masks.
*/
/*
* Private data
*/
/*
* Only provide these if we're supporting Wolfson AC97 devices.
*/
#if WM_AC97
/*
* Function prototypes
*/
static WM_REGVAL private_CalcPdwValue( WM_DEVICE_HANDLE hDevice,
WM_POWERFLAG powerSections
);
static WM_POWERFLAG private_CalcTouchPower( WM_DEVICE_HANDLE hDevice );
/*-----------------------------------------------------------------------------
* Function: WM97PowerUp
*
* Called to power up the specific sections of the chip on behalf of this
* driver.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* driverId The device ID (e.g. WM_DRIVER_TOUCH)
* powerSections The sections to power up.
*
* Returns: WMSTATUS
* See WMStatus.h.
*---------------------------------------------------------------------------*/
WMSTATUS WM97PowerUp( WM_DEVICE_HANDLE hDevice,
WM_DRIVER_ID driverId,
WM_POWERFLAG powerSections
)
{
#if WM_CACHE_POWER_STATE
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
#endif /* WM_CACHE_POWER_STATE */
WMSTATUS status;
WM_POWERFLAG newPowered = 0; /* What should be powered when we finish */
WM_POWERFLAG powerUp; /* What should be but isn't yet */
WM_REGVAL powerReg;
WM_POWERFLAG currentPower;
/*
* Work out what we need powered on.
* newPowered is what will be powered on at the end.
* powerUp is what will be powered up which isn't currently.
*
* Note: there are things which need to be done even if the codec is
* powered up, since some codecs start up with everything on. In this
* case we don't need to power anything up, but we still need to do
* other things such as enabling on-board amplifiers (for example).
*/
newPowered = calcPowered( hDevice, driverId, powerSections, 0, ¤tPower );
powerUp = newPowered & ~currentPower;
/*
* If the AC Link's not powered up, enable the controller to use the AC link
* and do a warm reset to start it up.
*/
if ( !(currentPower & WM_POWER_LINK) )
{
WMPlatformACLinkEnableController( hDevice );
status = WMWake( hDevice );
if ( WM_ERROR( status ) )
{
goto error;
}
}
/*
* Get the current reading if necessary.
*/
#if WM_CACHE_POWER_STATE
if ( pDeviceContext->v_pWMData &&
(pDeviceContext->v_pWMData->flags & WM_POWERREG_VALID)
)
{
powerReg = pDeviceContext->v_pWMData->powerReg[PWR_REG_1];
}
else
#endif /* WM_CACHE_POWER_STATE */
{
status = WMRead( hDevice, WM97_POWER_CONTROL, &powerReg );
if ( WM_ERROR( status ) )
{
goto error;
}
#if WM_CACHE_POWER_STATE
if ( pDeviceContext->v_pWMData )
{
pDeviceContext->v_pWMData->flags |= WM_POWERREG_VALID;
}
#endif /* WM_CACHE_POWER_STATE */
}
/*
* Enable audio.
* Recommended power-up sequence is
* PR5, PR3, PR2, PR1, PR0, PR6
* (PR4 is automatic on wake-up)
*
* Note: we use newPowered in this test (instead of powerUp)
* because there are things we may still need to do if the
* audio starts up powered up.
* We do not want to do any of this if we are only powering up the
* touch part of the device.
*/
if ( ( newPowered & WM_POWER_AUDIO ) && ( powerUp & ~WM_POWER_TOUCH ) )
{
/*
* The 9712 defaults to no ramp-down - turn it on (clear it) to
* avoid clicks on muting, powerup/down, etc.
*/
if ( IS_WM9712_FAMILY( hDevice ) )
{
status = WMClearField( hDevice, WM9712_ADD_FUN2, WM9712_ADDFUN_RAMPDOWN );
if ( WM_ERROR( status ) )
{
WM_TRACE( hDevice,
( "WMPowerUp - couldn't enable rampdown: %s",
WMStatusText( status ) ) );
/*
* If this failed, something's gone seriously wrong - we can't read
* or we can't write - so there's no point trying to continue.
*/
goto error;
}
}
#if !WM_ZERO_DATA_DAC_SWITCH_ENABLE
/*
* Very quiet samples which swing from total silence to
* a small noise floor can cause problems as the stereo DAC
* mutes output only for for the truly silent sections.
* If this causes a problem the following code should cure it.
*/
if ( IS_WM9705_FAMILY( hDevice ) ||
IS_WM9712_FAMILY( hDevice ) ||
( IS_WM9713_FAMILY( hDevice ) && WM_REVISION_EQUALS( hDevice, WM_REV_A ) )
)
{
status = WMClearField( hDevice,
WM97_ADD_FUN_CONTROL,
WM97_ADDFUN_AMUTE
);
if ( WM_ERROR( status ) )
{
WM_TRACE( hDevice,
( "WMPowerUp - couldn't disable automute: %s",
WMStatusText( status ) ) );
/*
* If this failed, something's gone seriously wrong - we can't read
* or we can't write - so there's no point trying to continue.
*/
goto error;
}
}
/*
* When the DAC is operating at a sample rate other than 48KHz
* it will switch to 48 khz when enough silence is played.
*/
if ( IS_WM9713_FAMILY( hDevice ) && WM_REVISION_EQUALS( hDevice, WM_REV_A ) )
{
status = WMSetField( hDevice, WM9713_RESERVED_1,
WM9713_ZERO_DATA_SWITCH_DISABLE,
WM9713_ZERO_DATA_SWITCH_DISABLE );
if ( WM_ERROR( status ) )
{
WM_TRACE( hDevice,
( "WMPowerUp - couldn't disable zero data switch: %s",
WMStatusText( status ) ) );
/*
* If this failed, something's gone seriously wrong - we can't read
* or we can't write - so there's no point trying to continue.
*/
goto error;
}
}
else if ( IS_WM9712_FAMILY( hDevice ) )
{
status = WMSetField( hDevice, WM9712_ADD_FUN2,
WM9712_ZERO_DATA_SWITCH_DISABLE,
WM9712_ZERO_DATA_SWITCH_DISABLE );
if ( WM_ERROR( status ) )
{
WM_TRACE( hDevice,
( "WMPowerUp - couldn't disable zero data switch: %s",
WMStatusText( status ) ) );
/*
* If this failed, something's gone seriously wrong - we can't read
* or we can't write - so there's no point trying to continue.
*/
goto error;
}
}
#endif /* WM_ZERO_DATA_DAC_SWITCH_ENABLE */
/* Turn on the clock (PR5). */
if ( powerUp & WM_POWER_CLOCK )
{
powerReg &= ~WM97_PWR_CLOCK;
status = WMWrite( hDevice, WM97_POWER_CONTROL, powerReg );
if ( WM_ERROR( status ) )
{
goto error;
}
}
/* Turn on VREF (PR3). */
if ( powerUp & WM_POWER_VREF )
{
powerReg &= ~WM97_PWR_VREF;
status = WMWrite( hDevice, WM97_POWER_CONTROL, powerReg );
if ( WM_ERROR( status ) )
{
goto error;
}
/*
* For WM9713 both the PR3 in register 26h and
* MBIAS in register 3Ch must be cleared.
*/
status = WMClearField( hDevice,
WM9713_EXT_POWERDOWN_1,
WM9713_EXTPWR_MBIAS
);
if ( WM_ERROR( status ) )
{
goto error;
}
}
/*
* Turn on the mixers and input PGAs
* and for WM9712 only OUT2 (PR2).
*/
if ( powerUp & WM_POWER_MIXERS )
{
powerReg &= ~WM97_PWR_MIXERS;
status = WMWrite( hDevice, WM97_POWER_CONTROL, powerReg );
if ( WM_ERROR( status ) )
{
goto error;
}
if ( IS_WM9713_FAMILY( hDevice ) )
{
/*
* For WM9713 both the PR2 in register 26h and
* mixers in register 3Ch must be cleared.
*/
status = WMClearField( hDevice,
WM9713_EXT_POWERDOWN_1,
( WM9713_EXTPWR_MONOMIX |
WM9713_EXTPWR_SPEAKERMIX |
WM9713_EXTPWR_HPMIX_RIGHT |
WM9713_EXTPWR_HPMIX_LEFT )
);
if ( WM_ERROR( status ) )
{
goto error;
}
/*
* For WM9713 both the PR2 in register 26h and
* input PGAs in register 3Eh must be cleared.
*/
status = WMClearField( hDevice,
WM9713_EXT_POWERDOWN_2,
( WM9713_EXTPWR_MIC_PREAMP_B |
WM9713_EXTPWR_MIC_PREAMP_A |
WM9713_EXTPWR_MIC_B |
WM9713_EXTPWR_MIC_A |
WM9713_EXTPWR_MONOIN |
WM9713_EXTPWR_LINEIN_RIGHT |
WM9713_EXTPWR_LINEIN_LEFT )
);
if ( WM_ERROR( status ) )
{
goto error;
}
}
}
/* Turn on the DACs (PR1) */
if ( powerUp & WM_POWER_AUDIO_DACS )
{
powerReg &= ~WM97_PWR_DAC;
status = WMWrite( hDevice, WM97_POWER_CONTROL, powerReg );
if ( WM_ERROR( status ) )
{
goto error;
}
if ( IS_WM9713_FAMILY( hDevice ) )
{
/*
* For WM9713 both the PR1 in register 26h and
* DACs in register 3Ch must be cleared.
*/
status = WMClearField( hDevice,
WM9713_EXT_POWERDOWN_1,
( WM9713_EXTPWR_DAC_LEFT |
WM9713_EXTPWR_DAC_RIGHT |
WM9713_EXTPWR_AUXDAC |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -