blob: 9a73c445d74c90b4df18b2450c1e8312a1081e82 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Vdaa VoiceDAA interface implementation file
*
* Distributed by:
* Silicon Laboratories, Inc
*
* This file contains proprietary information.
* No dissemination allowed without prior written permission from
* Silicon Laboratories, Inc.
*
* File Description:
* This is the implementation file for the main VoiceDAA API.
*
*/
#include "../config_inc/si_voice_datatypes.h"
#include "../inc/si_voice_ctrl.h"
#include "../inc/si_voice_timer_intf.h"
#include "../inc/vdaa.h"
#include "../inc/vdaa_registers.h"
#include "../config_inc/vdaa_api_config.h"
#define WriteReg pVdaa->deviceId->ctrlInterface->WriteRegister_fptr
#define ReadReg pVdaa->deviceId->ctrlInterface->ReadRegister_fptr
#define pVdaaHW pVdaa->deviceId->ctrlInterface->hCtrl
#define WriteRegX deviceId->ctrlInterface->WriteRegister_fptr
#define ReadRegX deviceId->ctrlInterface->ReadRegister_fptr
#define pVdaaHWX deviceId->ctrlInterface->hCtrl
#define LOGPRINT_PREFIX "VDAA: "
/*
** Static VDAA driver functions
*/
/*
** Function: isVerifiedDAA
**
** Description:
** Verifies addressed channel is DAA
**
** Input Parameters:
** pVdaa: pointer to SiVoiceChanType or vdaaChanType
**
** Return:
** Verified DAA
** Not DAA RC_CHANNEL_TYPE_ERR
**
*/
static int isVerifiedDAA(vdaaChanType *pVdaa)
{
uInt8 data = ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV);
if ( (data & 0x40) == 0 ) /*This bit is always 1 for DAA*/
{
LOGPRINT("%sDAA device not detected\n",LOGPRINT_PREFIX);
return RC_CHANNEL_TYPE_ERR;
}
else
{
/* For Si3050, the value will be zero initially (calloc), for Si32178/9, this will
* be non-zero (Rev B).
*/
if(pVdaa->deviceId->chipRev == 0)
{
/* Read Device ID and store it */
/* NOTE: in earlier releases we also read the line side info here. This is now done
Vdaa_duringPowerUpLineside since the information we read was always 0.
*/
data = pVdaa->ReadRegX(pVdaa->pVdaaHWX,pVdaa->channel,SYS_LINE_DEV_REV);
pVdaa->deviceId->chipRev= data&0xF;
#ifdef ENABLE_DEBUG
LOGPRINT("%sChipRev = 0x%x\n", LOGPRINT_PREFIX, pVdaa->deviceId->chipRev);
#endif
}
}
return RC_NONE;
}
#if 0 /* Removed for now since it isn't used, keeping code as reference */
/*
** Function: probeDaisyChain
**
** Description:
** Identify how many VDAA devices are in daisychain
** Only called if channel 0 has be previously qualified
** as a VDAA.
**
** Input Parameters:
** pVdaa: pointer to SiVoiceChanType or vdaaChanType
**
** Return:
** number of channels in daisy chain
**
*/
static int probeDaisyChain (vdaaChanType *pVdaa)
{
int i=0;
WriteReg(pVdaaHW,BROADCAST,PCMRX_CNT_LO,0x23); /* Broadcast */
while ((ReadReg(pVdaaHW,(uInt8)i++,PCMRX_CNT_LO) == 0x23)
&&(i<=16)); /* Count number of channels */
return i-1; /* Return number of channels */
}
#endif
/*
**
** ------ VDAA CONFIGURATION FUNCTIONS -----
**
*/
/*
** Function: Vdaa_RingDetectSetup
**
** Description:
** configure ring detect setup
**
** Returns:
**
*/
#ifndef DISABLE_VDAA_RING_DETECT_SETUP
extern vdaa_Ring_Detect_Cfg Vdaa_Ring_Detect_Presets[];
int Vdaa_RingDetectSetup (vdaaChanType *pVdaa,int32 preset)
{
uInt8 regTemp = 0;
TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2) & 0xfB;
regTemp |= Vdaa_Ring_Detect_Presets[preset].rdi<<2;
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL1) & 0xfe;
regTemp |= Vdaa_Ring_Detect_Presets[preset].rt&1;
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL1,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL2) & 0xef;
regTemp |= ((Vdaa_Ring_Detect_Presets[preset].rt>>1)<<4);
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL3,
Vdaa_Ring_Detect_Presets[preset].rfwe<<1);
regTemp = (Vdaa_Ring_Detect_Presets[preset].rdly&0x3) << 6;
regTemp |= Vdaa_Ring_Detect_Presets[preset].rmx ;
WriteReg(pVdaaHW,pVdaa->channel,RNG_VLD_CTRL1,regTemp);
regTemp = (Vdaa_Ring_Detect_Presets[preset].rdly>>2) << 7;
regTemp |= Vdaa_Ring_Detect_Presets[preset].rto << 3 ;
regTemp |= Vdaa_Ring_Detect_Presets[preset].rcc ;
WriteReg(pVdaaHW,pVdaa->channel,RNG_VLD_CTRL2,regTemp);
regTemp = Vdaa_Ring_Detect_Presets[preset].rngv << 7;
regTemp |= Vdaa_Ring_Detect_Presets[preset].ras ;
WriteReg(pVdaaHW,pVdaa->channel,RNG_VLD_CTRL3,regTemp);
regTemp = Vdaa_Ring_Detect_Presets[preset].rpol<<1;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL4,regTemp);
return RC_NONE;
}
#endif
/*
** Function: Vdaa_TXAudioGainSetup
**
** Description:
** configure tx audio gain
**
** Returns:
**
**
*/
#ifndef DISABLE_VDAA_AUDIO_GAIN_SETUP
extern vdaa_audioGain_Cfg Vdaa_audioGain_Presets[];
int Vdaa_TXAudioGainSetup (vdaaChanType *pVdaa,int32 preset)
{
uInt8 regTemp = 0;
TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
if(Vdaa_audioGain_Presets[preset].xga2 == XGA_ATTEN)
{
regTemp = 0x10;
}
regTemp |= Vdaa_audioGain_Presets[preset].acgain2 ;
WriteReg(pVdaaHW,pVdaa->channel,TX_GN_CTRL2,regTemp);
regTemp = 0;
if(Vdaa_audioGain_Presets[preset].xga3 == XGA_ATTEN)
{
regTemp = 0x10 ;
}
regTemp |= Vdaa_audioGain_Presets[preset].acgain3 ;
WriteReg(pVdaaHW,pVdaa->channel,TX_GN_CTRL3,regTemp);
if(Vdaa_audioGain_Presets[preset].cpEn)
{
WriteReg(pVdaaHW,pVdaa->channel,TXCALL_PROG_ATTEN,
Vdaa_audioGain_Presets[preset].callProgress);
}
return RC_NONE;
}
# endif
/*
** Function: Vdaa_RXAudioGainSetup
**
** Description:
** configure rx audio gain
**
** Returns:
**
**
*/
#ifndef DISABLE_VDAA_AUDIO_GAIN_SETUP
extern vdaa_audioGain_Cfg Vdaa_audioGain_Presets[];
int Vdaa_RXAudioGainSetup (vdaaChanType *pVdaa,int32 preset)
{
uInt8 regTemp = 0;
TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
if(Vdaa_audioGain_Presets[preset].xga2 == XGA_ATTEN)
{
regTemp = 0x10;
}
regTemp |= Vdaa_audioGain_Presets[preset].acgain2 ;
WriteReg(pVdaaHW,pVdaa->channel,RX_GN_CTRL2,regTemp);
regTemp = 0;
if(Vdaa_audioGain_Presets[preset].xga3 == XGA_ATTEN)
{
regTemp = 0x10;
}
regTemp |= Vdaa_audioGain_Presets[preset].acgain3 ;
WriteReg(pVdaaHW,pVdaa->channel,RX_GN_CTRL3,regTemp);
if(Vdaa_audioGain_Presets[preset].cpEn)
{
WriteReg(pVdaaHW,pVdaa->channel,RXCALL_PROG_ATTEN,
Vdaa_audioGain_Presets[preset].callProgress);
}
return RC_NONE;
}
#endif
/*
** Function: Vdaa_PCMSetup
**
** Description:
** configure pcm format, clocking and edge placement
**
** Returns:
**
**
*/
#ifndef DISABLE_VDAA_PCM_SETUP
extern vdaa_PCM_Cfg Vdaa_PCM_Presets [];
int Vdaa_PCMSetup (vdaaChanType *pVdaa,int32 preset)
{
uInt8 regTemp = 0;
TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regTemp = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL)&0xe0;
regTemp |= Vdaa_PCM_Presets[preset].pcm_tri;
regTemp |= Vdaa_PCM_Presets[preset].pcmHwy << 1;
regTemp |= Vdaa_PCM_Presets[preset].pcmFormat << 3;
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,regTemp);
return RC_NONE;
}
#endif
/*
** Function: Vdaa_PCMTimeSlotSetup
**
** Description:
** configure pcm timeslot
**
** Returns:
**
*/
int Vdaa_PCMTimeSlotSetup (vdaaChanType *pVdaa, uInt16 rxcount, uInt16 txcount)
{
uInt8 data = 0;
uInt8 pcmStatus;
TRACEPRINT( pVdaa, "rxcount = %u txcount = %u\n", (unsigned int)rxcount,
(unsigned int)txcount);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
/* Disable PCM if enabled - restore after updating timeslots */
pcmStatus = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
if (pcmStatus&0x20)
{
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,pcmStatus&~(0x20));
}
/*Storing 10 bit value of Transmit PCM sample in REG 34 and REG 35[0:1]*/
data = (uInt8)(txcount & 0xff);
WriteReg(pVdaaHW,pVdaa->channel,PCMTX_CNT_LO,data);
data = (uInt8)(txcount >> 8) ;
WriteReg(pVdaaHW,pVdaa->channel,PCMTX_CNT_HI,data);
/*Storing 10 bit value of Receive PCM sample in REG 34 and REG 35[0:1]*/
data = (uInt8)(rxcount & 0xff);
WriteReg(pVdaaHW,pVdaa->channel,PCMRX_CNT_LO,data);
data = (uInt8)(rxcount >> 8);
WriteReg(pVdaaHW,pVdaa->channel,PCMRX_CNT_HI,data);
/* Enable back the PCM after storing the values*/
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,pcmStatus);
return RC_NONE;
}
/*
** Function: Vdaa_CountrySetup
**
** Description:
** configure country specific settings
**
** Returns:
**
**
*/
#ifndef DISABLE_VDAA_COUNTRY_SETUP
extern vdaa_Country_Cfg Vdaa_Country_Presets [];
int Vdaa_CountrySetup (vdaaChanType *pVdaa,int32 preset)
{
uInt8 regTemp = 0;
TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2) & 0xFD;
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp); /* disable hybrid */
regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL1) & 0xFD;
regTemp |= Vdaa_Country_Presets[preset].rz << 1 ;
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL1,regTemp);
regTemp = Vdaa_Country_Presets[preset].dcr;
regTemp |= Vdaa_Country_Presets[preset].ilim<<1;
regTemp |= Vdaa_Country_Presets[preset].mini<<4;
regTemp |= Vdaa_Country_Presets[preset].dcv<<6;
WriteReg(pVdaaHW,pVdaa->channel,DC_TERM_CTRL,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,AC_TERM_CTRL) & 0xF0;
regTemp |= Vdaa_Country_Presets[preset].acim;
WriteReg(pVdaaHW,pVdaa->channel,AC_TERM_CTRL,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,SPRK_QNCH_CTRL) & 0xAF;
regTemp |= ((Vdaa_Country_Presets[preset].ohs_sq >> 2)&1)<<4 ;
regTemp |= ((Vdaa_Country_Presets[preset].ohs_sq >> 3)&1)<<6 ;
WriteReg(pVdaaHW,pVdaa->channel,SPRK_QNCH_CTRL,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL1) & 0xBF;
regTemp |= ((Vdaa_Country_Presets[preset].ohs_sq >> 1)&1)<<6 ;
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL1,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL5) & 0xE7;
regTemp |= (Vdaa_Country_Presets[preset].ohs_sq&1)<<3 ;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL5,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2) & 0xFD;
regTemp |= (Vdaa_Country_Presets[preset].hbe)<<1 ;
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp);
return RC_NONE;
}
#endif
/*
** Function: Vdaa_HybridSetup
**
** Description:
** configure hybrid
**
*/
#ifndef DISABLE_VDAA_HYBRID_SETUP
extern vdaa_Hybrid_Cfg Vdaa_Hybrid_Presets [];
int Vdaa_HybridSetup (vdaaChanType *pVdaa,int32 preset)
{
uInt8 regSave = 0;
TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regSave = ReadReg(pVdaaHW,pVdaa->channel,CTRL2);
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regSave&0xFD); /* disable hybrid */
WriteReg(pVdaaHW,pVdaa->channel,HYB1,Vdaa_Hybrid_Presets[preset].hyb1);
WriteReg(pVdaaHW,pVdaa->channel,HYB2,Vdaa_Hybrid_Presets[preset].hyb2);
WriteReg(pVdaaHW,pVdaa->channel,HYB3,Vdaa_Hybrid_Presets[preset].hyb3);
WriteReg(pVdaaHW,pVdaa->channel,HYB4,Vdaa_Hybrid_Presets[preset].hyb4);
WriteReg(pVdaaHW,pVdaa->channel,HYB5,Vdaa_Hybrid_Presets[preset].hyb5);
WriteReg(pVdaaHW,pVdaa->channel,HYB6,Vdaa_Hybrid_Presets[preset].hyb6);
WriteReg(pVdaaHW,pVdaa->channel,HYB7,Vdaa_Hybrid_Presets[preset].hyb7);
WriteReg(pVdaaHW,pVdaa->channel,HYB8,Vdaa_Hybrid_Presets[preset].hyb8);
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,
regSave); /* Restore hybrid enable state at entry */
return RC_NONE;
}
#endif
/*
** Function: Vdaa_SetAudioMute
**
** Description:
** Control RX and TX mute
**
*/
int Vdaa_SetAudioMute(vdaaChanType *pVdaa, tMUTE mute)
{
uInt8 regData;
TRACEPRINT( pVdaa, "mode = %u\n", (unsigned int) mute);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regData = ReadReg(pVdaaHW,pVdaa->channel,TXRX_GN_CTRL);
switch(mute)
{
case MUTE_DISABLE_ALL:
regData = 0;
break;
case MUTE_DISABLE_RX:
regData &= 0x80;
break;
case MUTE_DISABLE_TX:
regData &= 0x08;
break;
case MUTE_ENABLE_RX:
regData |= 0x08;
break;
case MUTE_ENABLE_TX:
regData |= 0x80;
break;
case MUTE_ENABLE_ALL:
regData = 0x88;
break;
}
WriteReg(pVdaaHW,pVdaa->channel,TXRX_GN_CTRL,regData);
return RC_NONE;
}
/*
** Function: Vdaa_PCMStart
**
** Description:
** Enables PCM bus
**
*/
int Vdaa_PCMStart (vdaaChanType *pVdaa)
{
uInt8 data = 0;
TRACEPRINT( pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
/*Enable PCM transfers by setting REG 33[5]=1 */
data = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
data |= 0x20;
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,data);
return RC_NONE;
}
/*
** Function: Vdaa_PCMStop
**
** Description:
** Disables PCM bus
**
*/
int Vdaa_PCMStop (vdaaChanType *pVdaa)
{
uInt8 data = 0;
TRACEPRINT( pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
/*disable PCM transfers by setting REG 33[5]=0 */
data = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
data &= ~(0x20);
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,data);
return RC_NONE;
}
/*
** Function: Vdaa_SetInterruptMask
**
** Description:
** Enables interrupts based on passed 9-bit bitmask. Bit
** values defined by vdaaIntMask enum.
**
*/
int Vdaa_SetInterruptMask(vdaaChanType *pVdaa, vdaaIntMask bitmask)
{
uInt8 intMaskReg = 0;
uInt8 cviReg = 0;
TRACEPRINT( pVdaa, "mask = 0x%03x\n", (unsigned int)bitmask);
/* Channel validation */
if(pVdaa->channelType != DAA)
{
return RC_CHANNEL_TYPE_ERR;
}
intMaskReg = (uInt8)(bitmask & 0x00ff);
cviReg = ReadReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL);
cviReg |= (uInt8) ((bitmask >> 7) & 0x0002);
WriteReg (pVdaaHW,pVdaa->channel,INTE_MSK,intMaskReg);
WriteReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL,cviReg);
return RC_NONE;
}
/*
** Function: Vdaa_ReadRingDetectStatus
**
** Description:
** Reads ring detect/hook status
**
** Returns:
**
**
*/
int Vdaa_ReadRingDetectStatus (vdaaChanType *pVdaa,
vdaaRingDetectStatusType *pStatus)
{
uInt8 reg;
TRACEPRINT( pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
reg = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
pStatus->offhook = reg & 0x01;
pStatus->ringDetected = (reg & 0x4)>>2;
pStatus->onhookLineMonitor = (reg & 0x8)>>3;
pStatus->ringDetectedPos = (reg & 0x20)>>5;
pStatus->ringDetectedNeg = (reg & 0x40)>>6;
return RC_NONE;
}
/*
** Function: Vdaa_Init
**
** Description:
** Initialize VDAA, load general config parameters
**
*/
extern vdaa_General_Cfg Vdaa_General_Configuration;
int Vdaa_Init (vdaaChanType_ptr *pVdaa,int size)
{
uInt8 data;
int k;
int num_devices = 0;
TRACEPRINT( *pVdaa, "size = %d\n", size);
for (k=0; k<size; k++)
{
if(pVdaa[k]->channelType == PROSLIC)
{
continue; /* Skip if we know this is a ProSLIC, else check the device out */
}
if (isVerifiedDAA(pVdaa[k]) == RC_CHANNEL_TYPE_ERR)
{
pVdaa[k]->channelEnable = FALSE;
pVdaa[k]->error = RC_CHANNEL_TYPE_ERR;
pVdaa[k]->channelType = UNKNOWN;
DEBUG_PRINT(pVdaa[k], "%sVDAA not supported on this device\n",LOGPRINT_PREFIX);
continue;
}
else
{
pVdaa[k]->channelType = DAA;
}
if (pVdaa[k]->channelEnable)
{
/*Try to write innocuous register to test SPI is working*/
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,PCMRX_CNT_LO,0x5A);
data = pVdaa[k]->ReadRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,PCMRX_CNT_LO);
if (data != 0x5A)
{
pVdaa[k]->error = RC_SPI_FAIL;
pVdaa[k]->channelEnable = FALSE;
DEBUG_PRINT(pVdaa[k], "%sVDAA %d not communicating\n",LOGPRINT_PREFIX,
pVdaa[k]->channel);
}
else
{
num_devices++;
}
}
}
if(num_devices == 0)
{
DEBUG_PRINT(*pVdaa, "%sNo DAA devices detected\n", LOGPRINT_PREFIX);
return RC_SPI_FAIL;
}
for (k=0; k<size; k++)
{
if(pVdaa[k]->channelType != DAA)
{
continue; /* Skip PROSLIC or UNDEFINED ports */
}
if (pVdaa[k]->channelEnable)
{
/* Apply General Configuration parameters */
/* No need to read-modify-write here since registers are in their reset state */
data = (Vdaa_General_Configuration.pwmm << 4) |
(Vdaa_General_Configuration.pwmEnable << 3);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,CTRL1, data);
data = (Vdaa_General_Configuration.inte << 7) | (Vdaa_General_Configuration.intp
<< 6) | 0x03;
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,CTRL2, data);
data = (Vdaa_General_Configuration.hssm << 3);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,SMPL_CTRL, data);
data = (Vdaa_General_Configuration.iire << 4);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,INTL_CTRL1, data);
data = (Vdaa_General_Configuration.rcald << 4);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,RES_CALIB, data);
data = (Vdaa_General_Configuration.full2 << 4);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,AC_TERM_CTRL, data);
data = (Vdaa_General_Configuration.lvfd) | (Vdaa_General_Configuration.filt <<
1) |
(Vdaa_General_Configuration.foh << 5) | (Vdaa_General_Configuration.full << 7);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,DAA_CTRL5, data);
data = (Vdaa_General_Configuration.spim << 6);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,PCM_SPI_CTRL, data);
data = (Vdaa_General_Configuration.cvp) | (Vdaa_General_Configuration.cvs << 2);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,LN_VI_THRESH_INTE_CTRL,
data);
data = (Vdaa_General_Configuration.gce << 1) | (Vdaa_General_Configuration.rg1
<< 2);
pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,SPRK_QNCH_CTRL, data);
/* Enable Lineside Device */
Vdaa_PowerupLineside(pVdaa[k]);
}
}
DEBUG_PRINT(*pVdaa,"%sDAA initialization completed\n",LOGPRINT_PREFIX);
return RC_NONE;
}
/*
** Function: Vdaa_ReadLinefeedStatus
**
** Description:
** Read Status of Line Feed
**
** Returns:
** RC_VDAA_ILOOP_OVLD if LCS >= 0x1F
** - no overload
**
*/
int Vdaa_ReadLinefeedStatus (vdaaChanType *pVdaa,int8 *vloop, int16 *iloop)
{
int16 regTemp = 0x1F;
uInt8 iloop_reg; /* REG 12[4:0] = Loop current*/
TRACEPRINT( pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regTemp &= ReadReg(pVdaaHW,pVdaa->channel,LSIDE_STAT);
iloop_reg = (uInt8)regTemp;
*iloop = (regTemp*LCS_SCALE_NUM) /
LCS_SCALE_DEN; /* Multiply the read result by 3.3mA/bit*/
*vloop = (int8) ReadReg(pVdaaHW,pVdaa->channel,LINE_VOLT_STAT);
if(*vloop & 0x80)
{
*vloop = ~(*vloop - 1)*(-1);
}
if (iloop_reg == 0x1F)
{
return RC_VDAA_ILOOP_OVLD;
}
return RC_NONE;
}
/*
** Function: Vdaa_GetInterrupts
**
** Description:
** Get Interrupts
**
** Returns:
** number of interrupts
**
*/
int Vdaa_GetInterrupts (vdaaChanType *pVdaa,vdaaIntType *pIntData)
{
uInt8 data = 0;
int j;
TRACEPRINT( pVdaa, "\n", NULL);
pIntData->number = 0;
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
data = ReadReg(pVdaaHW,pVdaa->channel,INTE_SRC); /*Snapshot Interrupts*/
WriteReg(pVdaaHW,pVdaa->channel,INTE_SRC,~(data)); /*Clear interrupts*/
for (j=0; j<8; j++)
{
if (data &(1<<j))
{
pIntData->irqs[pIntData->number] = j;
pIntData->number++;
}
}
data = ReadReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL);
if (data &(0x08)) /*to determine if CVI Interrupt is set*/
{
pIntData->irqs[pIntData->number] = CVI;
pIntData->number++;
data &= ~(0x08);
WriteReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL,data);
}
return pIntData->number;
}
/*
** Function: Vdaa_ClearInterrupts
**
** Description:
** Clear Interrupts
**
** Returns:
**
**
*/
int Vdaa_ClearInterrupts (vdaaChanType *pVdaa)
{
uInt8 data = 0;
TRACEPRINT( pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
WriteReg(pVdaaHW,pVdaa->channel,INTE_SRC,
0x00); /* Clear interrupts in REG 4 by writing 0's*/
/*Clear CVI interrupt by writing 0 at REG 44[3]*/
data = ReadReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL);
WriteReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL,data&0xF7);
return RC_NONE;
}
/*
** Function: Vdaa_GetHookStatus
**
** Description:
** Read VDAA Hook Status
**
** Return Values -
** VDAA_ONHOOK
** VDAA_OFFHOOK
** VDAA_ONHOOK_MONITOR
** RC_INVALID_HOOK_STATUS
*/
uInt8 Vdaa_GetHookStatus (vdaaChanType *pVdaa)
{
uInt8 data;
TRACEPRINT( pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
data &= 0x09; /* Look at only ONHM and OH */
if((data & 0x80)&&(data & 0x01))
{
return VDAA_ONHOOK_MONITOR;
}
else if (data & 0x01)
{
return VDAA_OFFHOOK;
}
else
{
return VDAA_ONHOOK;
}
}
/*
** Function: Vdaa_SetHookStatus
**
** Description:
** Set VDAA Hook switch to ONHOOK, OFFHOOK,
** or ONHOOK_MONITOR
**
*/
int Vdaa_SetHookStatus (vdaaChanType *pVdaa,uInt8 newHookStatus)
{
uInt8 data= 0 ;
TRACEPRINT( pVdaa, "hookstate = %u\n", (unsigned int) newHookStatus);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
switch (newHookStatus)
{
case VDAA_DIG_LOOPBACK:
/*Setting REG6[4]=1,REG5[0]=0,REG5[3]=0*/
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
data |= 0x10;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
data &= ~(0x09);
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
break;
case VDAA_ONHOOK:
/*Setting REG6[4]=0,REG5[0]=0,REG5[3]=0*/
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
data &= 0xF6;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
data &= 0xEF;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
break;
case VDAA_OFFHOOK:
/*Setting REG6[4]=0,REG5[0]=1,REG5[3]=0*/
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
data &= 0xF7;
data |= 0x01;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
data &= 0xEF;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
break;
case VDAA_ONHOOK_MONITOR:
/*Setting REG6[4]=0,REG5[0]=0,REG5[3]=1*/
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
data &= 0xFE;
data |= 0x08;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
data &= 0xEF;
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
break;
default:
return RC_UNSUPPORTED_OPTION;
}
return RC_NONE;
}
/*
** Function: Vdaa_SetLoopbackMode
**
** Description:
** Loopback mode control
**
*/
int Vdaa_SetLoopbackMode(vdaaChanType_ptr pVdaa, tLpbkMode lpbk_mode,
tLpbkStatus lpbk_status)
{
uInt8 regData;
TRACEPRINT(pVdaa, "lpbk_mode = %u lpbk_status = %d\n", (unsigned int) lpbk_mode,
(unsigned int) lpbk_status);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
switch(lpbk_mode)
{
case LPBK_NONE:
/* Disable all loopback types, regardless of lpbk_status */
regData = ReadReg(pVdaaHW,pVdaa->channel,CTRL1);
if(regData & 0x02)
{
WriteReg(pVdaaHW,pVdaa->channel,CTRL1, regData & ~(0x02));
}
regData = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL3);
if(regData & 0x01)
{
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL3,0);
}
regData = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
if(regData & 0x80)
{
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL, regData & ~(0x80));
}
break;
case LPBK_IDL:
if(lpbk_status)
{
regData = ReadReg(pVdaaHW,pVdaa->channel,CTRL1);
WriteReg(pVdaaHW,pVdaa->channel,CTRL1, regData | 0x02);
}
else
{
regData = ReadReg(pVdaaHW,pVdaa->channel,CTRL1);
WriteReg(pVdaaHW,pVdaa->channel,CTRL1, regData & ~(0x02));
}
break;
case LPBK_DDL:
if(lpbk_status)
{
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL3, 0x01);
}
else
{
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL3, 0);
}
break;
case LPBK_PCML:
if(lpbk_status)
{
regData = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL, regData | 0x80);
}
else
{
regData = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL, regData & ~(0x80));
}
break;
default:
return RC_UNSUPPORTED_OPTION;
}
return RC_NONE;
}
/*
** Function: Vdaa_ADCCal
**
** Description:
** This function calibrates the VDAA ADC manually
**
*/
int Vdaa_ADCCal (vdaaChanType_ptr pVdaa, int32 size)
{
uInt8 regTemp = 0;
int32 i;
TRACEPRINT(pVdaa, "size = %d\n", (int) size);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
for(i = 0; i < size; i++)
{
/* Clear the previous ADC Calibration data by toggling CALZ*/
regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL2);
regTemp |= 0x80;
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
regTemp &= ~0x80;
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL2); /*disable auto cal*/
regTemp |= 0x20;
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
regTemp |= 0x40; /*initiate manual cal*/
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
regTemp &= ~0x40;
WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
pVdaa++;
}
return RC_NONE;
}
/*
** Function: Vdaa_EnableWatchdog
**
** Description:
** Enables watchdog timer
**
*/
int Vdaa_EnableWatchdog(vdaaChanType_ptr pVdaa)
{
uInt8 regTemp;
TRACEPRINT(pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2);
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp | 0x10);
return RC_NONE;
}
/*
** Function: Vdaa_SetHybridEnable
**
** Description:
** Enables watchdog timer
**
*/
int Vdaa_SetHybridEnable(vdaaChanType_ptr pVdaa, int enable)
{
uInt8 regTemp;
TRACEPRINT(pVdaa, "enable = %d\n", enable);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2);
if(enable)
{
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp | 0x02);
}
else
{
WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp & ~(0x02));
}
return RC_NONE;
}
/*
** Function: Vdaa_SoftReset
**
** Description:
** Execute soft reset
**
*/
int Vdaa_SoftReset(vdaaChanType_ptr pVdaa)
{
TRACEPRINT(pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
WriteReg(pVdaaHW,pVdaa->channel,CTRL1,0x80);
return RC_NONE;
}
/*
** Function: Vdaa_ReadFDTStatus
**
** Description:
** Read FDT bit
**
** Returns:
** 0 - Frame Not Detected
** 1 - Frame Detected
**
*/
int Vdaa_ReadFDTStatus(vdaaChanType_ptr pVdaa)
{
TRACEPRINT(pVdaa, "\n", NULL);
return (ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV) & 0x40);
}
/*
** Function: Vdaa_PowerupLineside
**
** Description:
** Power up lineside device
**
*/
int Vdaa_PowerupLineside(vdaaChanType_ptr pVdaa)
{
uInt8 data;
TRACEPRINT(pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,0); /* Powerup lineside device */
/* We do a double read to give the front end time to power up and sync up with the system side.. */
data = ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV);
data = 0;
data = ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV);
pVdaa->deviceId->lsRev= ((data&0x3C)>>2);
data = pVdaa->ReadRegX(pVdaa->pVdaaHWX,pVdaa->channel,SYS_LINE_DEV_REV);
pVdaa->deviceId->lsType= ((data&~(0xF))>>4);
return RC_NONE;
}
/*
** Function: Vdaa_PowerdownLineside
**
** Description:
** Power down lineside device
**
*/
int Vdaa_PowerdownLineside(vdaaChanType_ptr pVdaa)
{
TRACEPRINT(pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,0x10);
return RC_NONE;
}
/*
** Function: Vdaa_PrintDebugData
**
** Description:
** Dump of VDAA register space
**
** Input Parameters:
** pVdaa: pointer to SiVoiceChanType or vdaaChanType
**
*/
int Vdaa_PrintDebugData (vdaaChanType *pVdaa)
{
#ifdef ENABLE_DEBUG
int i;
for (i=0; i<60; i++)
{
LOGPRINT ("%sRegister %d = %X\n",LOGPRINT_PREFIX,i,ReadReg(pVdaaHW,
pVdaa->channel,i));
}
#endif
return RC_NONE;
}
/*
** Function: Vdaa_InitLineInUseCheck
**
** Description:
** Set line in use test limits
**
** Input Parameters:
** liuCfg: pointer to vdaa_LIU_Config
** minOnV: minimum acceptable onhook voltage (below indicates parallel handset)
** minOffV: minimum acceptable offhook voltage (below indicates parallel handset)
** minOffI: minimum acceptable offhook loop current (below indicates parallel handset)
**
*/
int Vdaa_InitLineInUseCheck(vdaa_LIU_Config *liuCfg, int8 minOnV, int8 minOffV,
int16 minOffI)
{
TRACEPRINT_NOCHAN("min0nV = %d minoffV = %d minOffI = %d\n", minOnV, minOffV,
minOffI);
liuCfg->status = PAR_HANDSET_NOT_DETECTED;
liuCfg->min_onhook_vloop = minOnV;
liuCfg->min_offhook_vloop = minOffV;
liuCfg->min_offhook_iloop = minOffI;
return RC_NONE;
}
/*
** Function: Vdaa_CheckForLineInUse
**
** Description:
** Monitor LVCS to detect intrusion or parallel handset
**
** Input Parameters:
** pVdaa: pointer to SiVoiceChanType or vdaaChanType
** liuCfg: pointer to vdaa_LIU_Config
**
** Output Parameters:
**
** Return:
** VDAA_ONHOOK - line is onhook
** VDAA_OFFHOOK - line is offhook (in use)
**
*/
uInt8 Vdaa_CheckForLineInUse(vdaaChanType *pVdaa, vdaa_LIU_Config *liuCfg)
{
int8 vloop;
int16 iloop;
TRACEPRINT(pVdaa, "\n", NULL);
if(pVdaa->channelType != DAA)
{
return RC_IGNORE;
}
/* Check voltage and current */
Vdaa_ReadLinefeedStatus(pVdaa, &vloop,&iloop);
if(vloop < 0)
{
vloop *= -1;
}
liuCfg->measured_iloop = iloop;
liuCfg->measured_vloop = vloop;
liuCfg->status = PAR_HANDSET_NOT_DETECTED;
/* Read hookswitch status */
if(Vdaa_GetHookStatus(pVdaa) == VDAA_OFFHOOK)
{
if((vloop < liuCfg->min_offhook_vloop)||(iloop < liuCfg->min_offhook_iloop))
{
liuCfg->status = PAR_HANDSET_DETECTED;
}
return VDAA_OFFHOOK;
}
else
{
if(vloop < liuCfg->min_onhook_vloop)
{
liuCfg->status = PAR_HANDSET_DETECTED;
}
return VDAA_ONHOOK;
}
}