📄 pmic_audio.cpp
字号:
/*!
* @brief This variable maintains the current state of the Voice CODEC.
*
* This variable tracks the current state of the Voice CODEC audio hardware
* along with any information that is required by the device driver to
* manage the hardware (e.g., callback functions and event notification
* masks).
*
* The initial values represent the reset/power on state of the Voice CODEC.
*/
static PMIC_AUDIO_VCODEC_STATE vCodec = {
(PMIC_AUDIO_HANDLE)NULL, /* handle */
HANDLE_FREE, /* handleState */
AUDIO_DATA_BUS_2, /* busID */
NETWORK_MODE, /* protocol */
BUS_SLAVE_MODE, /* masterSlave */
USE_4_TIMESLOTS, /* numSlots */
(PMIC_AUDIO_CALLBACK)NULL, /* callback */
(PMIC_AUDIO_EVENTS)NULL, /* eventMask */
CLOCK_IN_CLIB, /* clockIn */
VCODEC_RATE_8_KHZ, /* samplingRate */
VCODEC_CLI_13MHZ, /* clockFreq */
NO_INVERT, /* invert */
USE_TS0, /* timeslot */
USE_TS2, /* secondary timeslot */
PMIC_AUDIO_VCODEC_CONFIG(INPUT_HIGHPASS_FILTER |
OUTPUT_HIGHPASS_FILTER),/* config */
(PMIC_AUDIO_INPUT_CONFIG)NULL, /* inputConfig */
/* leftChannelMic */
{ NO_MIC, /* mic */
MICROPHONE_OFF, /* micOnOff */
CURRENT_TO_VOLTAGE, /* ampMode */
MIC_GAIN_0DB /* gain */
},
/* rightChannelMic */
{ NO_MIC, /* mic */
MICROPHONE_OFF, /* micOnOff */
AMP_OFF, /* ampMode */
MIC_GAIN_0DB /* gain */
}
};
/*!
* @brief This maintains the current state of the External Stereo Input.
*/
typedef struct
{
PMIC_AUDIO_HANDLE handle; /*!< Handle used to access the
External Stereo Inputs. */
HANDLE_STATE handleState; /*!< Current handle state. */
PMIC_AUDIO_CALLBACK callback; /*!< Event notification callback
function pointer. */
PMIC_AUDIO_EVENTS eventMask; /*!< Event notification mask. */
PMIC_AUDIO_STEREO_IN_GAIN inputGain; /*!< External Stereo Input
amplifier gain level. */
} PMIC_AUDIO_EXT_STEREO_IN_STATE;
/*!
* @brief This maintains the current state of the External Stereo Input.
*
* This variable tracks the current state of the External Stereo Input audio
* hardware along with any information that is required by the device driver
* to manage the hardware (e.g., callback functions and event notification
* masks).
*
* The initial values represent the reset/power on state of the External
* Stereo Input.
*/
static PMIC_AUDIO_EXT_STEREO_IN_STATE extStereoIn = {
(PMIC_AUDIO_HANDLE)NULL, /* handle */
HANDLE_FREE, /* handleState */
(PMIC_AUDIO_CALLBACK)NULL, /* callback */
(PMIC_AUDIO_EVENTS)NULL, /* eventMask */
STEREO_IN_GAIN_0DB /* inputGain */
};
/*!
* @brief This maintains the current state of the Audio Output Section.
*/
typedef struct
{
PMIC_AUDIO_OUTPUT_PORT outputPort; /*!< Current audio
output port. */
PMIC_AUDIO_OUTPUT_PGA_GAIN outputStDACPGAGain; /*!< Output PGA gain
level. */
PMIC_AUDIO_OUTPUT_PGA_GAIN outputVCodecPGAGain; /*!< Output PGA gain
level. */
PMIC_AUDIO_OUTPUT_PGA_GAIN outputExtStereoInPGAGain; /*!< Output PGA
gain level.
*/
PMIC_AUDIO_OUTPUT_BALANCE_GAIN balanceLeftGain; /*!< Left channel
balance gain
level. */
PMIC_AUDIO_OUTPUT_BALANCE_GAIN balanceRightGain; /*!< Right channel
balance gain
level. */
PMIC_AUDIO_MONO_ADDER_OUTPUT_GAIN monoAdderGain; /*!< Mono adder gain
level. */
PMIC_AUDIO_OUTPUT_CONFIG config; /*!< Audio output
section config
options. */
} PMIC_AUDIO_AUDIO_OUTPUT_STATE;
/*!
* @brief This variable maintains the current state of the Audio Output Section.
*
* This variable tracks the current state of the Audio Output Section.
*
* The initial values represent the reset/power on state of the Audio
* Output Section.
*/
static PMIC_AUDIO_AUDIO_OUTPUT_STATE audioOutput = {
(PMIC_AUDIO_OUTPUT_PORT)NULL, /* outputPort */
OUTPGA_GAIN_0DB, /* outputStDACPGAGain */
OUTPGA_GAIN_0DB, /* outputVCodecPGAGain */
OUTPGA_GAIN_0DB, /* outputExtStereoInPGAGain */
BAL_GAIN_0DB, /* balanceLeftGain */
BAL_GAIN_0DB, /* balanceRightGain */
MONOADD_GAIN_0DB, /* monoAdderGain */
(PMIC_AUDIO_OUTPUT_CONFIG)0 /* config */
};
/*! The current headset status. */
static HEADSET_STATUS headsetState = NO_HEADSET;
/*! Define a 1 ms wait interval that is needed to ensure that certain
* hardware operations are successfully completed.
*/
static const unsigned long delay_1ms = 1;
/*! Define a handle to a mutex object for implementing mutual exclusion.
*
* Note that because this source file will be part of a DLL, we cannot
* just call CreateMutex() here to initialize the mutex handle. Attempting
* to do so will result in a LNK4210 warning when the linker tries to
* create the DLL. This warning indicates that no CRT (C runtime) code
* is available to handle non-trivial static initializers (such as those
* that involve a function call). Therefore, we must defer the CreateMutex()
* call until the DLL is actually loaded by the Device Manager and
* activated. This will result in a call to pmic_audio_driver_init() where
* we can finally make our CreateMutex() call.
*
* The mutex handle is released and the mutex destroyed when the Device
* Manager deactivates the device and pmic_audio_driver_deinit() is called.
*/
static HANDLE mutex = NULL;
/*! Declare a global flag that is only set to TRUE when the powerdown handler
* is running. This allows us to bypass any timed delay calls that would
* have normally been made. Because the powerdown handler runs at priority 0
* with interrupts disabled, it cannot do anything that would cause it to
* block or otherwise wait.
*/
static BOOL g_audioPowerdown = FALSE;
/*! We need to have a globally accessible handle to the timed delay event
* object so that the powerdown handler can forcibly cancel an in-progress
* timer. All in-progress timed delays must be immediately cancelled so
* that the thread can wake up and quickly release the critical section
* (which is guarded by the mutex handle that was declared above).
* Otherwise, the powerdown handler will block when it too tries to
* acquire the critical section.
*/
static HANDLE hTimedDelay = NULL;
/* Prototypes for all static audio driver functions. */
static PMIC_STATUS pmic_read_reg(const pmic_control_register regID,
const unsigned *regValue);
static PMIC_STATUS pmic_write_reg(const pmic_control_register regID,
const unsigned regValue,
const unsigned regMask);
static inline void down_interruptible(HANDLE hMutex);
static inline void up(HANDLE hMutex);
static PMIC_STATUS pmic_adc_convert(const unsigned short channel,
const unsigned short *adcResult);
static PMIC_STATUS pmic_audio_mic_boost_enable(void);
static PMIC_STATUS pmic_audio_mic_boost_disable(void);
static PMIC_STATUS pmic_audio_close_handle(const PMIC_AUDIO_HANDLE handle);
static PMIC_STATUS pmic_audio_reset_device(const PMIC_AUDIO_HANDLE handle);
/*************************************************************************
* Audio device access APIs.
*************************************************************************
*/
/*!
* @name General Setup and Configuration APIs
* Functions for general setup and configuration of the PMIC Audio
* hardware.
*/
/*@{*/
/*!
* @brief Request exclusive access to the PMIC Audio hardware.
*
* Attempt to open and gain exclusive access to a key PMIC audio hardware
* component (e.g., the Stereo DAC or the Voice CODEC). Depending upon the
* type of audio operation that is desired and the nature of the audio data
* stream, the Stereo DAC and/or the Voice CODEC will be a required hardware
* component and needs to be acquired by calling this function.
*
* If the open request is successful, then a numeric handle is returned
* and this handle must be used in all subsequent function calls to complete
* the configuration of either the Stereo DAC or the Voice CODEC and along
* with any other associated audio hardware components that will be needed.
*
* The same handle must also be used in the close call when use of the PMIC
* audio hardware is no longer required.
*
* The open request will fail if the requested audio hardware component has
* already been acquired by a previous open call but not yet closed.
*
* @param[out] handle Device handle to be used for subsequent PMIC
* audio API calls.
* @param[in] device The required PMIC audio hardware component.
*
* @retval PMIC_SUCCESS If the open request was successful
* @retval PMIC_PARAMETER_ERROR If the handle argument is NULL.
* @retval PMIC_ERROR If the audio hardware component is
* unavailable.
*/
PMIC_STATUS PmicAudioOpen(
PMIC_AUDIO_HANDLE *const handle,
const PMIC_AUDIO_SOURCE device)
{
PMIC_STATUS rc = PMIC_ERROR;
if (handle == (PMIC_AUDIO_HANDLE *)NULL)
{
/* Do not dereference a NULL pointer. */
return PMIC_PARAMETER_ERROR;
}
/* We only need to acquire a mutex here because the interrupt handler
* never modifies the device handle or device handle state. Therefore,
* we don't need to worry about conflicts with the interrupt handler
* or the need to execute in an interrupt context.
*
* But we do need a critical section here to avoid problems in case
* multiple calls to pmic_audio_open() are made since we can only allow
* one of them to succeed.
*/
down_interruptible(mutex);
/* Check the current device handle state and acquire the handle if
* it is available.
*/
if ((device == STEREO_DAC) && (stDAC.handleState == HANDLE_FREE))
{
stDAC.handle = (PMIC_AUDIO_HANDLE)(&stDAC);
stDAC.handleState = HANDLE_IN_USE;
*handle = stDAC.handle;
rc = PMIC_SUCCESS;
}
else if ((device == VOICE_CODEC) && (vCodec.handleState == HANDLE_FREE))
{
vCodec.handle = (PMIC_AUDIO_HANDLE)(&vCodec);
vCodec.handleState = HANDLE_IN_USE;
*handle = vCodec.handle;
rc = PMIC_SUCCESS;
}
else if ((device == EXTERNAL_STEREO_IN) &&
(extStereoIn.handleState == HANDLE_FREE))
{
extStereoIn.handle = (PMIC_AUDIO_HANDLE)(&extStereoIn);
extStereoIn.handleState = HANDLE_IN_USE;
*handle = extStereoIn.handle;
rc = PMIC_SUCCESS;
} else {
*handle = AUDIO_HANDLE_NULL;
}
/* Exit the critical section. */
up(mutex);
return rc;
}
/*!
* @brief Terminate further access to the PMIC audio hardware.
*
* Terminate further access to the PMIC audio hardware that was previously
* acquired by calling pmic_audio_open(). This now allows another thread to
* successfully call pmic_audio_open() to gain access.
*
* Note that we will shutdown/reset the Voice CODEC or Stereo DAC as well as
* any associated audio input/output components that are no longer required.
*
* @param[in] handle Device handle from pmic_audio_open() call.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -