blob: 2abf925ac57256b3429f056908c89b945f141d25 [file] [log] [blame]
/*****************************************************************************
* Copyright Statement:
* --------------------
* This software is protected by Copyright and the information contained
* herein is confidential. The software may not be copied and the information
* contained herein may not be used or disclosed except with the written
* permission of MediaTek Inc. (C) 2012
*
* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
*
* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
*
*****************************************************************************/
/*******************************************************************************
*
* Filename:
* ---------
* tone.c
*
* Project:
* --------
* MTK6208
*
* Description:
* ------------
* Tone Interface
*
* Author:
* -------
* -------
*
*==============================================================================
* HISTORY
* Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*------------------------------------------------------------------------------
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
*------------------------------------------------------------------------------
* Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*==============================================================================
*******************************************************************************/
#include "kal_public_api.h"
#include "kal_general_types.h"
#include "dcl.h"
#include "reg_base.h"
#include "sync_data.h"
#include "l1aud_common_def.h"
#include "l1audio.h"
#include "media.h"
#include "afe.h"
#include "am.h"
#include "speech_def.h"
// #include "audio_def.h"
#include "afe_def.h"
#define KT_INIT_AMP 0x3FFF
#define TONE_INIT_AMP 0x1FFF
static struct
{
const L1SP_Tones *tonelist;
const L1SP_QTMF *curr_qtmf;
void (*handler)(void);
uint32 gpt;
uint16 aud_id;
uint16 amp;
bool bQTMF;
bool isRun;
} tone;
static struct
{
uint32 gpt;
uint16 aud_id;
int8 lock;
uint8 volume1;
int8 digital_gain_index;
bool isRun;
} keytone;
#define DSP_QTMF_FREQ(f1,f2,f3,f4) { DSP_TONE_F2A = (f1); \
DSP_TONE_F2B = (f2); \
DSP_TONE_F1A = (tone.bQTMF)?(f3):0; \
DSP_TONE_F1B = (tone.bQTMF)?(f4):0; \
Data_Sync_Barrier(); }
#define DSP_KT_FREQ(f1,f2) { DSP_TONE_F2A = (f1); \
DSP_TONE_F2B = (f2); \
Data_Sync_Barrier(); }
/* When Audio Ramp Down Enable, MCU waits until Audio RampDown of DSP. If the time of DSP's RampDown exceeds this value, the beginning part of Tone maybe be cut */
#define SW_WAIT_AUDIO_RAMPDOWN (6)
/* ------------------------------------------------------------------------------ */
/* Functions for Playing Comfort Tones */
/* ------------------------------------------------------------------------------ */
static void tonePlayOff( void *data );
void toneStop_FlushQueue( void *data )
{
if(AM_IsToneOn())
{
SGPT_CTRL_START_T start;
start.u2Tick = 1;
start.pfCallback = toneStop_FlushQueue;
start.vPara = data;
DclSGPT_Control( tone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
} else {
L1Audio_ClearFlag( tone.aud_id );
}
}
static void toneStop( void *data )
{
uint16 tone_ctrl;
SGPT_CTRL_START_T start;
if( !L1Audio_CheckFlag( tone.aud_id ) )
return;
tone_ctrl = (DSP_TONE_CTRL2 << 8) + DSP_TONE_CTRL1;
switch( tone_ctrl ) {
case 0:
if (tone.isRun) {
tone.isRun = false;
tone.bQTMF = false;
AM_ToneOff();
DP_KT_ATT = 0;
Data_Sync_Barrier();
L1Audio_SetEvent( tone.aud_id, 0 );
// unapply hardware mute during tone playback
*AFE_AMCU_CON1 &= ~0x30;
Data_Sync_Barrier();
#if defined(__BT_SUPPORT__)
if( L1SP_GetSpeechMode() == SPH_MODE_LINEIN_VIA_BT_CORDLESS )
{
*DP_AUDIO_PAR = (*DP_AUDIO_PAR & 0xFF) | 0x1000; // set back to cordless mode
Data_Sync_Barrier();
}
#endif
}
start.u2Tick = 1;
start.pfCallback = toneStop_FlushQueue;
start.vPara = data;
DclSGPT_Control( tone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
break;
case 0x202:
DSP_TONE_CTRL1 = 4;
DSP_TONE_CTRL2 = 4;
Data_Sync_Barrier();
default:
start.u2Tick = 1;
start.pfCallback = toneStop;
start.vPara = data;
DclSGPT_Control( tone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
break;
}
}
static void tonePlayOn( void *data )
{
uint16 dura;
if( tone.bQTMF )
tone.curr_qtmf = (L1SP_QTMF *)tone.tonelist + (uint32)data;
else
tone.curr_qtmf = (L1SP_QTMF *)(tone.tonelist + (uint32)data);
// apply hardware mute during tone playback
*AFE_AMCU_CON1 |= 0x0C;
Data_Sync_Barrier();
DSP_QTMF_FREQ( tone.curr_qtmf->freq1, tone.curr_qtmf->freq2,
tone.curr_qtmf->freq3, tone.curr_qtmf->freq4 );
DSP_TONE_CTRL1 = 1;
DSP_TONE_CTRL2 = 1;
Data_Sync_Barrier();
if( ( dura = tone.curr_qtmf->on_duration / 10 ) > 0 ) {
SGPT_CTRL_START_T start;
start.u2Tick = dura;
start.pfCallback = tonePlayOff;
start.vPara = 0;
DclSGPT_Control( tone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
}
}
static void toneMute( void *data )
{
int32 dura = (int32)data;
uint16 tone_ctrl;
SGPT_CTRL_START_T start;
tone_ctrl = (DSP_TONE_CTRL2 << 8) + DSP_TONE_CTRL1;
switch( tone_ctrl ) {
case 0:
start.u2Tick = dura+1;
start.pfCallback = tonePlayOn;
start.vPara = (void *)(kal_uint32)tone.curr_qtmf->next_tone;
DclSGPT_Control( tone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
break;
case 0x202:
DSP_TONE_CTRL1 = 4;
DSP_TONE_CTRL2 = 4;
Data_Sync_Barrier();
default:
start.u2Tick = 1;
start.pfCallback = toneMute;
start.vPara = (void*)((dura>0)?dura-1:0);
DclSGPT_Control( tone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
break;
}
}
static void tonePlayOff( void *data )
{
uint16 dura = tone.curr_qtmf->off_duration / 10;
if( dura == 0 )
toneStop( 0 );
else
toneMute( (void*)(kal_uint32)dura );
}
static void toneHandler( void *data ) /* This function works in L1Audio Task */
{
(void)data;
if( tone.handler != 0 )
tone.handler();
}
void toneInit( uint16 aud_id )
{
tone.aud_id = aud_id;
tone.handler = 0;
L1Audio_SetEventHandler( aud_id, toneHandler );
tone.gpt = DclSGPT_Open( DCL_GPT_CB ,0 );
DSP_TONE_CTRL1 = 0;
tone.amp = TONE_INIT_AMP;
tone.bQTMF = false;
DP_KT_ATT = 0;
Data_Sync_Barrier();
#ifdef ANALOG_AFE_PATH_EXIST
AFE_TurnOnFIR( L1SP_TONE );
#endif // ANALOG_AFE_PATH_EXIST
}
/* ------------------------------------------------------------------------------ */
/* Tone Interface */
/* ------------------------------------------------------------------------------ */
void TONE_SetOutputDevice( uint8 device )
{
#if 0 // def ANALOG_AFE_PATH_EXIST
/* under construction !*/
#endif
}
void TONE_SetOutputVolume( uint8 volume1, int8 digital_gain_index )
{
#if 0 // def ANALOG_AFE_PATH_EXIST
/* under construction !*/
#endif
}
/*****************************************************************************
* FUNCTION
* TONE_PlayQTMF
* DESCRIPTION
* This function is used to play comfort tones.
* Totally 4 frequencies can be generated
*
* PARAMETERS
* tonelist - QTMF list
* RETURNS
* None.
* GLOBALS AFFECTED
* None
*****************************************************************************/
void TONE_PlayQTMF( const L1SP_QTMF *tonelist )
{
if( L1Audio_CheckFlag( tone.aud_id ) )
return;
tone.bQTMF = true;
TONE_Play((const L1SP_Tones *)tonelist);
}
/*****************************************************************************
* FUNCTION
* TONE_Play
* DESCRIPTION
* This function is used to play comfort tones.
*
* PARAMETERS
* tonelist - Tone list
* RETURNS
* None.
* GLOBALS AFFECTED
* None
*****************************************************************************/
void TONE_Play( const L1SP_Tones *tonelist )
{
// FIXME:
return;
if(AM_IsSpeechOn()){/* Prevent Speech from being muted, becuase Tone/KT with volume = 0 results in DigitalGain = 0 */
/*
uint8 volume;
#ifdef ANALOG_AFE_PATH_EXIST
int8 digital_gain_index;
AFE_GetOutputVolume(L1SP_TONE, &volume, &digital_gain_index);
#else
AFE_DigitalOnly_GetOutputVolume(L1SP_TONE, &volume);
#endif // ANALOG_AFE_PATH_EXIST
if(0 == volume)
return;
*/
}
if( L1Audio_CheckFlag( tone.aud_id ) )
return;
if( L1Audio_CheckFlag( keytone.aud_id ) ) {
KT_Stop();
while( L1Audio_CheckFlag( keytone.aud_id ) )
kal_sleep_task( AUD_1TICK(1) );
}
if( AM_IsSpeechOn() )
{
DP_KT_ATT = 0x4000;
Data_Sync_Barrier();
}
#if defined(__BT_SUPPORT__)
if( L1SP_IsBluetoothOn() ){
if( L1SP_GetSpeechMode() == SPH_MODE_LINEIN_VIA_BT_CORDLESS )
*DP_AUDIO_PAR = (*DP_AUDIO_PAR & 0xFF) | 0x2000; // set to earphone mode
DSP_TONE_AMP1 = (TONE_INIT_AMP >> 2); /* degrade bluetooth tone volume by 12dB */
DSP_TONE_AMP2 = (TONE_INIT_AMP >> 2); /* degrade bluetooth tone volume by 12dB */
}else
#endif
{
DSP_TONE_AMP1 = tone.amp;
DSP_TONE_AMP2 = tone.amp;
}
Data_Sync_Barrier();
L1Audio_SetFlag( tone.aud_id );
tone.tonelist = tonelist;
AM_ToneOn();
tonePlayOn( 0 );
tone.isRun = true;
}
/*****************************************************************************
* FUNCTION
* TONE_Stop
* DESCRIPTION
* This function is used to stop playing comfort tones.
*
* PARAMETERS
* None
* RETURNS
* None
* GLOBALS AFFECTED
* None
*****************************************************************************/
void TONE_Stop( void )
{
DclSGPT_Control(tone.gpt ,SGPT_CMD_STOP, 0);
toneStop( 0 );
}
void TONE_StopAndWait( void )
{
int I;
AM_FlushQFunction();
TONE_Stop();
for( I = 0; ; I++ ) {
if ( !AM_IsToneOn() )
break;
ASSERT_REBOOT(I < 20);
kal_sleep_task( AUD_1TICK(2) );
}
kal_sleep_task( AUD_1TICK(2) );//wait AFE also updated
}
void TONE_SetAmplitude( int16 amp )
{
tone.amp = (uint16)amp;
}
void TONE_SetFIR( bool enable )
{
if( enable ) {
#if 0 // def ANALOG_AFE_PATH_EXIST
/* under construction !*/
#endif // ANALOG_AFE_PATH_EXIST
}else{
#if 0 // def ANALOG_AFE_PATH_EXIST
/* under construction !*/
#endif
}
}
void TONE_SetHandler( void (*handler)(void) )
{
tone.handler = handler;
}
/* ------------------------------------------------------------------------------ */
/* Keytone Interface */
/* ------------------------------------------------------------------------------ */
void ktStop_FlushQueue( void *data )
{
if(AM_IsKeyToneOn())
{
SGPT_CTRL_START_T start;
start.u2Tick = 1;
start.pfCallback = ktStop_FlushQueue;
start.vPara = data;
DclSGPT_Control( keytone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
} else {
L1Audio_ClearFlag( keytone.aud_id );
}
}
static void ktStop( void *data )
{
SGPT_CTRL_START_T start;
if( !L1Audio_CheckFlag( keytone.aud_id ) )
return;
switch( DSP_TONE_CTRL2 ) {
case 0:
if (keytone.isRun) {
keytone.isRun = false;
AM_KeyToneOff();
}
start.u2Tick = 1;
start.pfCallback = ktStop_FlushQueue;
start.vPara = data;
DclSGPT_Control( keytone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
//L1Audio_ClearFlag( keytone.aud_id );
break;
case 2:
DSP_TONE_CTRL2 = 4;
Data_Sync_Barrier();
default:
start.u2Tick = 1;
start.pfCallback = ktStop;
start.vPara = data;
DclSGPT_Control( keytone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
break;
}
}
void ktInit( uint16 aud_id )
{
keytone.aud_id = aud_id;
keytone.lock = 0;
keytone.volume1 = 160;
keytone.digital_gain_index = 0;
keytone.gpt = DclSGPT_Open(DCL_GPT_CB,0);
DSP_TONE_CTRL2 = 0;
DSP_TONE_AMP2 = KT_INIT_AMP;
Data_Sync_Barrier();
#if 0 // def ANALOG_AFE_PATH_EXIST
/* under construction !*/
#endif
}
void ktLock( void )
{
ASSERT( keytone.lock < 8 );
keytone.lock++;
}
void ktUnlock( void )
{
ASSERT( keytone.lock > 0 );
keytone.lock--;
}
void KT_SetOutputDevice( uint8 device )
{
if( L1Audio_CheckFlag( keytone.aud_id ) ) {
KT_Stop();
while( L1Audio_CheckFlag( keytone.aud_id ) )
kal_sleep_task( AUD_1TICK(1) );
}
#if 0 // def ANALOG_AFE_PATH_EXIST
/* under construction !*/
#endif
}
void KT_SetOutputVolume( uint8 volume1, int8 digital_gain_index )
{
keytone.volume1 = volume1;
keytone.digital_gain_index = digital_gain_index;
}
/*****************************************************************************
* FUNCTION
* KT_Play
* DESCRIPTION
* This function is used to play keytone.
*
* PARAMETERS
* freq1 - The first frequency
* freq2 - The second frequency
* duration - Duration of the tone
* RETURNS
* None.
* GLOBALS AFFECTED
* None
*****************************************************************************/
void KT_Play( uint16 freq1, uint16 freq2, uint16 duration )
{
// FIXME:
return;
// endif
if( keytone.lock > 0 || keytone.volume1 == 0 )
return;
if( L1Audio_CheckFlag( keytone.aud_id ) )
return;
#if !defined(__DISABLE_SKIP_KEYTONE_DURING_TONE_PLAY__)
if( L1Audio_CheckFlag( tone.aud_id ) )
return;
#endif
if( L1Audio_CheckFlag( tone.aud_id ) ) {
TONE_Stop();
while( L1Audio_CheckFlag( tone.aud_id ) )
kal_sleep_task( AUD_1TICK(1) );
}
/* When Tone/KT with volume = 0 lets AFE set DigitalGain = 0, it causes the side effect. At the same time, Speech is muted, becuase digital gain is 0 */
if(AM_IsSpeechOn()){
/*
uint8 volume;
#ifdef ANALOG_AFE_PATH_EXIST
int8 digital_gain_index;
AFE_GetOutputVolume(L1SP_TONE, &volume, &digital_gain_index);
#else
AFE_DigitalOnly_GetOutputVolume(L1SP_TONE, &volume);
#endif // ANALOG_AFE_PATH_EXIST
if(0 == volume)
return;
*/
}
L1Audio_SetFlag( keytone.aud_id );
/* keytone in speech mode, need special care */
#if defined(__BT_SUPPORT__)
if( L1SP_IsBluetoothOn() ) {
DSP_TONE_AMP2 = KT_INIT_AMP >> 2; /* degrade bluetooth keytone volume by 12dB */
Data_Sync_Barrier();
#if 0
/* under construction !*/
/* under construction !*/
#else //#if 0
// FIXME: take care here! still no implement
ASSERT(0);
#endif //#if 0
}
else
#endif
if( AM_IsSpeechOn() ) { // && AFE_GetOutputDevice(L1SP_KEYTONE)==AFE_GetOutputDevice(L1SP_SPEECH) ) {
#if 0 // def ANALOG_AFE_PATH_EXIST
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
#else
DSP_TONE_AMP2 = KT_INIT_AMP;
#endif // ANALOG_AFE_PATH_EXIST
Data_Sync_Barrier();
}
else {
DSP_TONE_AMP2 = KT_INIT_AMP;
Data_Sync_Barrier();
#if 0
/* under construction !*/
/* under construction !*/
#else //#if 0
// FIXME: take care here! still no implement
ASSERT(0);
#endif //#if 0
}
DSP_KT_FREQ( freq1, freq2 );
DSP_TONE_CTRL2 = 1;
Data_Sync_Barrier();
keytone.isRun = true;
AM_KeyToneOn();
if( (duration = duration / 10) > 0 ) {
SGPT_CTRL_START_T start;
start.u2Tick = duration;
start.pfCallback = ktStop;
start.vPara = 0;
DclSGPT_Control( keytone.gpt, SGPT_CMD_START,(DCL_CTRL_DATA_T*)&start);
}
}
/*****************************************************************************
* FUNCTION
* KT_Stop
* DESCRIPTION
* This function is used to stop key tone playing.
*****************************************************************************/
void KT_Stop( void )
{
DclSGPT_Control( keytone.gpt, SGPT_CMD_STOP, 0);
ktStop( 0 );
}
void KT_StopAndWait(void)
{
int I;
AM_FlushQFunction();
KT_Stop();
for( I = 0; ; I++ ) {
if ( !AM_IsKeyToneOn() )
break;
ASSERT_REBOOT(I < 20);
kal_sleep_task( AUD_1TICK(2) );
}
kal_sleep_task( AUD_1TICK(2) );//wait AFE also updated
}
void KT_SetAmplitude( int16 amp )
{
DSP_TONE_AMP2 = amp;
Data_Sync_Barrier();
}
void KT_SetFIR( bool enable )
{
if( enable ){
#if 0
/* under construction !*/
/* under construction !*/
#endif //#if 0
} else {
#if 0
/* under construction !*/
/* under construction !*/
#endif //#if 0
}
}
/* To indicate if the keytone can be play */
kal_bool KT_IsPlayable(void)
{
if( keytone.lock > 0 || keytone.volume1 == 0 )
return KAL_FALSE;
if( L1Audio_CheckFlag( keytone.aud_id ) || L1Audio_CheckFlag( tone.aud_id ) )
return KAL_FALSE;
return KAL_TRUE;
}