📄 wm8753audio.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: WM8753Audio.c 2333 2005-10-20 14:06:34Z ib $
*
* This file contains platform-independent routines for controlling the audio
* operation on Wolfson 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 "WMPlatformI2S.h"
#include "WMPlatformSSP.h"
#include "WMPlatformDebug.h"
#include "WMGlobals.h"
#include "WM8753Audio.h"
#include "WM8753RegisterDefs.h"
#include "WMTestCommon.h"
#include "WMInternalTests.h"
/*
* Only build this if we're doing Audio support for WM8753 devices.
*/
#if WM_AUDIO && WM8753_FAMILY
#ifndef WM_MCLK_FREQUENCY
/*
* We need to know our MCLK frequency. This should be a value in Hz
* such as 12000000 (for 12MHz).
*/
# error Please define WM_MCLK_FREQUENCY (in Hz) in WMPlatformConfig.h
#endif
/*
* Global definitions
*/
/*
* The base for K, the fractional part of the fraction.
*/
#define PLL_K_BASE (1U << 22)
/*
* Which PLL to use.
*/
typedef enum tagWM8753_PLL
{
WM8753_PLL1 = 1,
WM8753_PLL2
} WM8753_PLL;
/*
* A macro which works out whether the voice interface is enabled.
*/
#if WM_VOICE
# define IS_VOICE_ENABLED( _pCtx ) \
(_pCtx->v_pWMData->audioData.flags & WM_AUDIO_VOICE_CONFIGURED)
#else
# define IS_VOICE_ENABLED( _pCtx ) FALSE
#endif
/*
* A macro which works out which interface to use.
* For HiFi playback it's HiFi. For Voice anything it's voice. For HiFi
* record it's HiFi if there is no voice, otherwise it's Voice.
*/
#define STREAM_USES_HIFI( _stream, _pCtx ) \
( ( WM_STREAM_HIFI_OUT == _stream ) || \
( WM_STREAM_HIFI_IN == _stream && !( IS_VOICE_ENABLED(_pCtx) ) ) \
)
/*
* Private data
*/
typedef struct tagSampleRateSetting
{
WM_SAMPLE_RATE dacRate; /* Requested DAC rate */
WM_SAMPLE_RATE adcRate; /* Requested ADC rate */
unsigned int pllFreq; /* PLL frequency required */
WM_REGVAL regSetting; /* Value of WM8753_SAMPLERATE_MASK field
or WM8753_VXCLK_DIV_MASK field */
} SampleRateSetting;
static const SampleRateSetting s_hifiRates[] =
{
/* First the matched sample rates */
{ 8000, 8000, 12288000, 0x06 },
{ 11025, 11025, 11289600, 0x18 },
{ 12000, 12000, 12288000, 0x08 },
{ 16000, 16000, 12288000, 0x0A },
{ 22050, 22050, 11289600, 0x1A },
{ 24000, 24000, 12288000, 0x1C },
{ 32000, 32000, 12288000, 0x0C },
{ 44100, 44100, 11289600, 0x10 },
{ 48000, 48000, 12288000, 0x00 },
{ 88200, 88200, 11289600, 0x1E },
{ 96000, 96000, 12288000, 0x0E },
/* Now the unmatched sample rates */
{ 8000, 44100, 11289600, 0x12 },
{ 8000, 48000, 12288000, 0x02 },
{ 44100, 8000, 11289600, 0x14 },
{ 48000, 8000, 12288000, 0x04 },
};
static const SampleRateSetting s_voiceRates[] =
{
{ 8000, 8000, 12288000, WM8753_VXCLK_DIV_6 },
{ 11025, 11025, 11289600, WM8753_VXCLK_DIV_4 },
{ 12000, 12000, 12288000, WM8753_VXCLK_DIV_4 },
{ 16000, 16000, 12288000, WM8753_VXCLK_DIV_3 },
{ 22050, 22050, 11289600, WM8753_VXCLK_DIV_2 },
{ 24000, 24000, 12288000, WM8753_VXCLK_DIV_2 },
{ 44100, 44100, 11289600, WM8753_VXCLK_DIV_1 },
{ 48000, 48000, 12288000, WM8753_VXCLK_DIV_1 },
};
#if WM_TESTING
typedef struct tagPLLCoeffTest
{
unsigned int MCLKFreq;
unsigned int targetFreq;
int N;
int K;
WM_BOOL divMclk;
} PLLCoeffTest;
static PLLCoeffTest s_PLLCoeffs[] =
{
{ 11910000, 11289600, 7, 0x25545F, FALSE },
{ 11910000, 12288000, 8, 0x103FF8, FALSE },
{ 12000000, 11289600, 7, 0x21B08A, FALSE },
{ 12000000, 12288000, 8, 0x0C49BA, FALSE },
{ 13000000, 11289600, 6, 0x3CA2F5, FALSE },
{ 13000000, 12288000, 7, 0x23F54A, FALSE },
{ 14400000, 11289600, 6, 0x116873, FALSE },
{ 14400000, 12288000, 6, 0x34E81B, FALSE },
{ 19200000, 11289600, 9, 0x1A1CAC, TRUE },
{ 19200000, 12288000, 10, 0x0F5C29, TRUE },
{ 19680000, 11289600, 9, 0x0B6D25, TRUE },
{ 19680000, 12288000, 9, 0x3F6028, TRUE },
{ 19800000, 11289600, 9, 0x07DDBE, TRUE },
{ 19800000, 12288000, 9, 0x3B8028, TRUE },
{ 24000000, 11289600, 7, 0x21B08A, TRUE },
{ 24000000, 12288000, 8, 0x0C49BA, TRUE },
{ 26000000, 11289600, 6, 0x3CA2F5, TRUE },
{ 26000000, 12288000, 7, 0x23F54A, TRUE },
{ 27000000, 11289600, 6, 0x2C2B25, TRUE },
{ 27000000, 12288000, 7, 0x1208A6, TRUE }
};
#endif /* WM_TESTING */
/*
* Function prototypes
*/
static WMSTATUS private_ConfigurePLL( WM_DEVICE_HANDLE hDevice,
WM8753_PLL pll,
unsigned int targetFreq
);
static void private_calcPLLCoefficients( unsigned int MCLKFreq,
unsigned int targetFreq,
int *pN,
int *pK,
WM_BOOL *pDivMclk
);
/*-----------------------------------------------------------------------------
* Function: WM8753SetSampleRate
*
* Called to set the sample rate in the audio-specific sections of the chip.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* stream The stream for which to set the sample rate
* sampleRate The requested sample rate.
*
* Returns: WMSTATUS
* See WMStatus.h.
*---------------------------------------------------------------------------*/
WMSTATUS WM8753SetSampleRate( WM_DEVICE_HANDLE hDevice,
WM_STREAM_ID stream,
WM_SAMPLE_RATE sampleRate
)
{
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
WMSTATUS status;
const SampleRateSetting *pSettings;
unsigned int nSettings;
unsigned int setting;
WM_REGVAL rateval;
unsigned int pllFreq;
WM8753_PLL pll;
WM_BOOL isHiFi;
WM_BOOL isMaster;
WM_BOOL found = FALSE;
/*
* Look up our sample rate setting.
* If the voice interface is enabled, we assume we will be set up
* as HiFi DAC + Voice codec, so the VXDAC and ADC sample rates are
* locked together. NB: In this mode, the only way to record on the
* HiFi interface is to set up a switch on the VX and HiFi clock lines
* - see App Note 0152.
*/
isHiFi = STREAM_USES_HIFI( stream, pDeviceContext );
if ( isHiFi )
{
pSettings = s_hifiRates;
nSettings = WM_ARRAY_COUNT( s_hifiRates );
pll = WM8753_PLL1;
isMaster = pDeviceContext->v_pWMData->audioData.flags & WM_AUDIO_HIFI_MASTER;
}
else
{
pSettings = s_voiceRates;
nSettings = WM_ARRAY_COUNT( s_voiceRates );
pll = WM8753_PLL2;
isMaster = pDeviceContext->v_pWMData->audioData.flags & WM_AUDIO_VOICE_MASTER;
}
/*
* Note: We don't currently handle whether ADC and DAC rates are
* compatible. The ADC and voice DAC will overwrite each other, and
* the HiFi DAC will just take the first option.
*/
if ( WM_IS_INPUT_STREAM( stream ) ) /* ADC */
{
for ( setting = 0; setting < nSettings; setting++ )
{
WM_SAMPLE_RATE adcRate = pSettings[ setting ].adcRate;
if ( sampleRate == adcRate )
{
rateval = pSettings[ setting ].regSetting;
pllFreq = pSettings[ setting ].pllFreq;
found = TRUE;
break;
}
}
}
else /* output stream - DAC */
{
for ( setting = 0; setting < nSettings; setting++ )
{
WM_SAMPLE_RATE dacRate = pSettings[ setting ].dacRate;
if ( sampleRate == dacRate )
{
rateval = pSettings[ setting ].regSetting;
pllFreq = pSettings[ setting ].pllFreq;
found = TRUE;
break;
}
}
}
if ( !found )
{
status = WMS_INVALID_PARAMETER;
goto error;
}
if ( isMaster )
{
/*
* Set up the PLL.
*/
status = private_ConfigurePLL( hDevice, pll, pllFreq );
if ( WM_ERROR( status ) )
{
goto error;
}
/*
* Write the sample rate to the codec.
*/
if ( isHiFi )
{
/*
* Set the HiFi codec sample rate.
*/
status = WMSetField( hDevice,
WM8753_SAMPLE_RATE_CTRL_1,
rateval << WM8753_SAMPLERATE_SHIFT,
WM8753_SAMPLERATE_MASK
);
if ( WM_ERROR( status ) )
{
goto error;
}
}
else
{
/*
* Set the voice codec sample rate.
*/
status = WMSetField( hDevice,
WM8753_CLOCK_CONTROL,
rateval, /* shift already in value */
WM8753_VXCLK_DIV_MASK
);
if ( WM_ERROR( status ) )
{
goto error;
}
}
}
else /* => slave */
{
/*
* Now set up the platform.
*/
if ( WM_IS_HIFI_STREAM( stream ) )
{
/*
* Set the I2S sample rate.
*/
status = WMPlatformI2SSetSampleRate( hDevice, sampleRate );
if ( WM_ERROR( status ) )
{
goto error;
}
}
}
/*
* We're done.
*/
return WMS_SUCCESS;
error:
return status;
}
/*-----------------------------------------------------------------------------
* Function: WM8753ConfigureInterface
*
* Configures the streaming format for the link for the given interface.
* Note: this is not required for AC'97 streams - HIFI and MONO on AC'97
* codecs.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* audioIF the interface to configure
* isMaster whether the codec masters the link
* format the streaming format to use
* width the number of bits per sample
* flags extra configuration flags
*
* Returns: WMSTATUS
* See WMStatus.h.
*---------------------------------------------------------------------------*/
WMSTATUS WM8753ConfigureInterface( WM_DEVICE_HANDLE hDevice,
WM_AUDIO_INTERFACE audioIF,
WM_BOOL isMaster,
WM_AUDIOIF_FORMAT format,
WM_AUDIOIF_WIDTH width,
WM_AUDIOIF_FLAGS flags
)
{
WM_DEVICE_CONTEXT *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
WMSTATUS status;
WM_REGTYPE reg;
WM_REGVAL controlVal = 0;
WM_REGVAL interfaceVal = 0, interfaceMask = 0;
WM_REGVAL sampleRateVal = 0, sampleRateMask = 0;
WM_REGVAL adcRateMode = 0;
WM8753_PLL pll;
/*
* Master or slave?
*/
if ( isMaster )
controlVal |= WM8753_MASTER;
else
controlVal |= WM8753_SLAVE;
/*
* Set data format.
*/
switch ( format )
{
case WM_AUDIOIF_I2S:
controlVal |= WM8753_DATA_FORMAT_I2S;
break;
case WM_AUDIOIF_LEFT_JUSTIFY:
controlVal |= WM8753_DATA_FORMAT_LJUST;
break;
case WM_AUDIOIF_RIGHT_JUSTIFY:
controlVal |= WM8753_DATA_FORMAT_RJUST;
break;
case WM_AUDIOIF_DSP_MODE_A:
controlVal |= WM8753_DATA_FORMAT_DSP | WM8753_DSP_MODE_A;
break;
case WM_AUDIOIF_DSP_MODE_B:
controlVal |= WM8753_DATA_FORMAT_DSP | WM8753_DSP_MODE_B;
break;
default:
WM_TRACE( hDevice, (
"WM8753ConfigureInterface: unsupported format %d",
format
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -