📄 wmauxadc.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: WMAuxADC.c 3497 2006-07-28 16:25:36Z marthur $
*
* This file contains platform-independent routines for controlling
* the analogue to digital converters on Wolfson codecs.
*
* Warning:
* This driver is specifically written for Wolfson Codecs. It is not a
* general CODEC device driver.
*
* -----------------------------------------------------------------------------*/
/*
* 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 WMSystemCallsAllowed returns TRUE.
*
* 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. However, the v_pADCData member
* can be relied on by functions in this file.
*/
/*
* Include files
*/
#include "WMCommon.h"
#include "WMGlobals.h"
#include "WMControlLink.h"
#include "WMPlatformACLink.h"
#include "WMDevice.h"
#include "WMTouch.h"
#include "WMAuxADC.h"
#include "WMTouchDefs.h"
#include "WMPower.h"
#if WM_AUXADC
/*
* Global definitions
*/
/* Mapping from ADC reading to bucket */
#define BUCKET_INDEX_FROM_ADCADR( _adcAdr ) (((_adcAdr) & WM_AUXADC_MASK) >> 12)
#define ADCADR_FROM_BUCKET_INDEX( _bucket ) (((_bucket) << 12) & WM_AUXADC_MASK)
/* Mapping from ADCVAL (e.g. WM_ADC_COMP1) to index for ADC details table
in Chipdefs */
#define INDEX_FROM_ADCVAL( _adcVal ) (_adcVal & 0x0FFF)
/* The active mask for the touch buckets */
#define XCOORD_BUCKET BUCKET_INDEX_FROM_ADCADR(WM_AUXADC_X_COORD)
#define YCOORD_BUCKET BUCKET_INDEX_FROM_ADCADR(WM_AUXADC_Y_COORD)
#define TOUCH_ACTIVE_MASK ((1 << XCOORD_BUCKET) | (1 << YCOORD_BUCKET))
/* Convert between ADCSEL, bucket and ADCADR */
#define BIT_MASK( _bucket ) (1U << (_bucket))
#define ADCSEL_FROM_BUCKET_MASK( _bucketMask ) ((_bucketMask) & WM_ADCSEL_MASK)
#define BUCKET_MASK_FROM_ADCSEL( _adcsel ) ((_adcsel))
#define ADCSEL_FROM_BUCKET_INDEX( _bucket ) ADCSEL_FROM_BUCKET_MASK( BIT_MASK( _bucket ) )
#define ADCSEL_FROM_ADCADR( _adcAdr ) ADCSEL_FROM_BUCKET_INDEX( BUCKET_INDEX_FROM_ADCADR(_adrAdr) )
/*
* The maximum number of attempts before we decide we're not getting data.
*/
#define SAMPLE_CYCLE_COUNT 10
/*
* The length of time (in microseconds) to wait between attempts if there's nothing
* in the FIFO. Note frame rate is 48 kHZ - i.e. ~20.83us per frame.
*/
#define SAMPLE_DATA_WAIT 50
/*
* The duration of a frame.
*/
#define FRAME_TIME 21
/*
* Private data
*/
/*
* Function prototypes
*/
static WMSTATUS private_PollADC( WM_DEVICE_HANDLE hDevice,
WM_REGVAL adc,
WM_REGVAL *pValue
);
#if WM_STREAM_AUXADC
static WMSTATUS private_SwitchStreaming( WM_DEVICE_HANDLE hDevice );
static WMSTATUS private_SampleADC( WM_DEVICE_HANDLE hDevice,
WM_REGVAL adc,
WM_REGVAL *pValue
);
static WM_REGVAL private_GetAdcSelVal( WM_DEVICE_HANDLE hDevice );
static WMSTATUS private_GetADCValue( WM_DEVICE_HANDLE hDevice );
static void private_PrepareBucket( WM_DEVICE_HANDLE hDevice, WM_REGVAL adcAdr );
#endif /* WM_STREAM_AUXADC */
/*-----------------------------------------------------------------------------
* Function: WMAuxADCInit
*
* Initialises the ADC functionality.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCInit( WM_DEVICE_HANDLE hDevice )
{
#if WM_STREAM_AUXADC || defined(DEBUG)
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
#endif /* WM_STREAM_AUXADC || DEBUG */
WMSTATUS status;
/*
* Take the mutex.
*/
if ( !WMLockGlobalData( hDevice ) )
{
status = WMS_LOCK_TIMED_OUT;
goto error0;
}
/* Check it's a device with touch panel */
if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
{
WM_TRACE( hDevice,
("WMAuxADCInit: There is no Auxiliary "
"ADC Support for this Wolfson Device! 0x%X",
pDeviceContext->deviceType
));
status = WMS_UNSUPPORTED;
goto error1;
}
#if WM_STREAM_AUXADC
if ( !(pDeviceContext->v_pADCData->flags & WM_DRVCTX_AUXADC_INITIALISED) )
{
int adc;
/*
* We don't have an ADC selected.
*/
pDeviceContext->v_pADCData->activeADCs = 0;
pDeviceContext->v_pADCData->flags &= ~WM_DRVCTX_AUXADC_TOUCH_STREAMING;
/*
* Now make sure all readings are marked invalid.
*/
for ( adc = 0; adc < ADC_COUNT; adc++ )
{
pDeviceContext->v_pADCData->reading[adc] = WM_INVALID_SAMPLE;
pDeviceContext->v_pADCData->lastReading[adc] = WM_INVALID_SAMPLE;
}
/* We're initialised now */
pDeviceContext->v_pADCData->flags |= WM_DRVCTX_AUXADC_INITIALISED;
}
#endif /* WM_STREAM_AUXADC */
/*
* Let other threads in.
*/
WMUnlockGlobalData( hDevice );
return WMS_SUCCESS;
error1:
WMUnlockGlobalData( hDevice );
error0:
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMAuxADCShutdown
*
* Shuts down the ADC functionality.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: void
*---------------------------------------------------------------------------*/
void WMAuxADCShutdown( WM_DEVICE_HANDLE hDevice )
{
/* Power down the auxiliary ADC functions. */
WMAuxADCPowerDown( hDevice, WM_POWER_AUXADC );
/* And shut down the Control Link. */
WMLinkShutdown( hDevice, WM_DRIVER_AUXADC );
}
/*-----------------------------------------------------------------------------
* Function: WMAuxADCStart
*
* Prepares the ADC functionality to generate readings of the appropriate type.
*
* Note the ADCs are mutually exclusive - selecting one deselects the previous
* one. The exceptions to this are the X- and Y-coordinates, which can be
* streamed along with the ADC reading.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* adcType Which ADC to read from.
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCStart( WM_DEVICE_HANDLE hDevice, WM_AUXADC_TYPE adcType )
{
WMSTATUS status;
/* Check we've got AUX ADC */
if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
{
status = WMS_UNSUPPORTED;
goto error0;
}
#if WM_STREAM_AUXADC
{
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
unsigned int bucket;
WM_REGVAL adcAdr;
/*
* We only have to do anything in streaming mode.
*/
/*
* Protect ourselves from interference.
*/
if ( !WMLockGlobalData( hDevice ) )
{
status = WMS_LOCK_TIMED_OUT;
goto error0;
}
/*
* Touch is a special case.
* Note WM_ADC_TOUCH is 0x0003, which is conveniently
* WM_ADC_X_COORD|WM_ADC_Y_COORD (0x0001|0x0002).
*/
if ( ( adcType & WM_ADC_TOUCH ) == adcType )
{
if ( pDeviceContext->v_pADCData->flags & WM_DRVCTX_AUXADC_TOUCH_STREAMING )
{
/* Nothing to do */
goto done;
}
pDeviceContext->v_pADCData->flags |= WM_DRVCTX_AUXADC_TOUCH_STREAMING;
/* Prepare the buckets */
bucket = BUCKET_INDEX_FROM_ADCADR( WM_AUXADC_X_COORD );
WM_ASSERT( hDevice, bucket < ADC_COUNT );
WM_ASSERT( hDevice, XCOORD_BUCKET == bucket );
pDeviceContext->v_pADCData->reading[bucket] = WM_INVALID_SAMPLE;
pDeviceContext->v_pADCData->lastReading[bucket] = WM_INVALID_SAMPLE;
pDeviceContext->v_pADCData->activeADCs |= 1 << bucket;
bucket = BUCKET_INDEX_FROM_ADCADR( WM_AUXADC_Y_COORD );
WM_ASSERT( hDevice, bucket < ADC_COUNT );
pDeviceContext->v_pADCData->reading[bucket] = WM_INVALID_SAMPLE;
pDeviceContext->v_pADCData->lastReading[bucket] = WM_INVALID_SAMPLE;
pDeviceContext->v_pADCData->activeADCs |= 1 << bucket;
}
else
{
/* Now look up the address */
WM_ASSERT( hDevice, adcType < pDeviceContext->pChipDef->adcCount);;
adcAdr = pDeviceContext->pChipDef->pAuxADCDetails[adcType].adcAdr;
WM_ASSERT( hDevice, 0 < adcAdr);
bucket = BUCKET_INDEX_FROM_ADCADR( adcAdr );
WM_ASSERT( hDevice, bucket < ADC_COUNT );
if ( pDeviceContext->v_pADCData->activeADCs & (1 << bucket) )
{
/* Nothing to do */
goto done;
}
/* And prepare the bucket */
private_PrepareBucket( hDevice, adcAdr );
/* Set streaming mode */
pDeviceContext->v_pADCData->flags |= WM_DRVCTX_AUXADC_ADC_STREAMING;
}
/*
* If we get here, we've got a change.
*/
status = private_SwitchStreaming( hDevice );
if ( WM_ERROR( status ) )
{
goto error1;
}
done:
/*
* Let other threads in.
*/
WMUnlockGlobalData( hDevice );
}
#endif /* WM_STREAM_AUXADC */
return WMS_SUCCESS;
#if WM_STREAM_AUXADC
error1:
/*
* Let other threads in.
*/
WMUnlockGlobalData( hDevice );
#endif /* WM_STREAM_AUXADC */
error0:
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMAuxADCSelect
*
* Prepares the ADC functionality to generate readings of the appropriate type,
* but doesn't start streaming.
*
* Note the ADCs are mutually exclusive - selecting one deselects the previous
* one. The exceptions to this are the X- and Y-coordinates, which can be
* streamed along with the ADC reading.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* adcType Which ADC to read from.
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCSelect( WM_DEVICE_HANDLE hDevice, WM_AUXADC_TYPE adcType )
{
WMSTATUS status = WMS_SUCCESS;
/* Check we've got AUX ADC */
if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
{
status = WMS_UNSUPPORTED;
goto error0;
}
#if WM_STREAM_AUXADC
{
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
WM_REGVAL adcAdr;
WM_BOOL adcStreaming = FALSE;
/*
* We only have to do anything in streaming mode.
*/
/*
* Protect ourselves from interference.
*/
if ( !WMLockGlobalData( hDevice ) )
{
status = WMS_LOCK_TIMED_OUT;
goto error0;
}
/*
* Touch is a special case, and should always use WMAuxADCStart.
* Note WM_ADC_TOUCH is 0x0003, which is conveniently
* WM_ADC_X_COORD|WM_ADC_Y_COORD (0x0001|0x0002).
*/
WM_ASSERT( hDevice, ( adcType & WM_ADC_TOUCH ) != adcType );
/* Remember whether the ADC has asked to stream. */
adcStreaming = pDeviceContext->v_pADCData->flags &
WM_DRVCTX_AUXADC_ADC_STREAMING;
/*
* If we're streaming, switch ADCs.
*/
if ( pDeviceContext->v_pADCData->flags & WM_DRVCTX_AUXADC_STREAMING )
{
status = WMAuxADCStart( hDevice, adcType );
}
else
{
/* Now look up the address */
WM_ASSERT( hDevice, adcType < pDeviceContext->pChipDef->adcCount);
adcAdr = pDeviceContext->pChipDef->pAuxADCDetails[adcType].adcAdr;
WM_ASSERT( hDevice, 0 < adcAdr);
/* And prepare the bucket */
private_PrepareBucket( hDevice, adcAdr );
/* Set streaming mode */
pDeviceContext->v_pADCData->flags |= WM_DRVCTX_AUXADC_ADC_STREAMING;
private_SwitchStreaming( hDevice );
}
/*
* If we're only streaming because of touch, keep it that way.
*/
if ( !adcStreaming )
{
pDeviceContext->v_pADCData->flags &=
~WM_DRVCTX_AUXADC_ADC_STREAMING;
}
/*
* Let other threads in.
*/
WMUnlockGlobalData( hDevice );
}
#endif /* WM_STREAM_AUXADC */
return WMS_SUCCESS;
error0:
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMAuxADCStop
*
* Stops the ADC functionality from generating readings of the appropriate type.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* adcType Which ADC to stop.
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCStop( WM_DEVICE_HANDLE hDevice, WM_AUXADC_TYPE adcType )
{
WMSTATUS status;
/* Check we've got AUX ADC */
if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
{
status = WMS_UNSUPPORTED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -