blob: a06ee353b04c308ee37bfa48f87ecd31f485af2f [file] [log] [blame]
/*
** Copyright (c) 2007-2010 by Silicon Laboratories
**
** $Id: si3226x_intf.c 1030 2009-09-01 22:59:44Z nizajerk@SILABS.COM $
**
** SI3226X_Intf.c
** SI3226X ProSLIC interface implementation file
**
** Author(s):
** laj
**
** 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 ProSLIC API and is used
** in the ProSLIC demonstration code.
**
*/
#include "si_voice_datatypes.h"
#include "si_voice_ctrl.h"
#include "si_voice_timer_intf.h"
#include "proslic.h"
#include "si3226x_intf.h"
#include "si3226x.h"
#include "si3226x_registers.h"
#include "../proslic_api_config.h"
#define PRAM_ADDR (334 + 0x400)
#define PRAM_DATA (335 + 0x400)
#define WriteReg pProslic->deviceId->ctrlInterface->WriteRegister_fptr
#define ReadReg pProslic->deviceId->ctrlInterface->ReadRegister_fptr
#define pProHW pProslic->deviceId->ctrlInterface->hCtrl
#define Reset pProslic->deviceId->ctrlInterface->Reset_fptr
#define Delay pProslic->deviceId->ctrlInterface->Delay_fptr
#define pProTimer pProslic->deviceId->ctrlInterface->hTimer
#define WriteRAM pProslic->deviceId->ctrlInterface->WriteRAM_fptr
#define ReadRAM pProslic->deviceId->ctrlInterface->ReadRAM_fptr
#define TimeElapsed pProslic->deviceId->ctrlInterface->timeElapsed_fptr
#define getTime pProslic->deviceId->ctrlInterface->getTime_fptr
#define SetSemaphore pProslic->deviceId->ctrlInterface->Semaphore_fptr
#define WriteRegX deviceId->ctrlInterface->WriteRegister_fptr
#define ReadRegX deviceId->ctrlInterface->ReadRegister_fptr
#define pProHWX deviceId->ctrlInterface->hCtrl
#define DelayX deviceId->ctrlInterface->Delay_fptr
#define pProTimerX deviceId->ctrlInterface->hTimer
#define WriteRAMX deviceId->ctrlInterface->WriteRAM_fptr
#define ReadRAMX deviceId->ctrlInterface->ReadRAM_fptr
#define getTimeX deviceId->ctrlInterface->getTime_fptr
#define TimeElapsedX deviceId->ctrlInterface->timeElapsed_fptr
#define BROADCAST 0xff
/*
** Externs
*/
/* General Configuration */
extern Si3226x_General_Cfg Si3226x_General_Configuration;
#ifdef SIVOICE_MULTI_BOM_SUPPORT
extern const proslicPatch SI3226X_PATCH_B_FLBK;
extern const proslicPatch SI3226X_PATCH_B_FIXRL;
extern const proslicPatch SI3226X_PATCH_C_FLBK;
extern const proslicPatch SI3226X_PATCH_C_QCUK;
extern const proslicPatch SI3226X_PATCH_C_LCQCUK;
extern const proslicPatch SI3226X_PATCH_C_CUK;
extern const proslicPatch SI3226X_PATCH_C_TSS;
extern const proslicPatch SI3226X_PATCH_C_TSS_ISO;
extern const proslicPatch SI3226X_PATCH_C_PBB5;
extern const proslicPatch SI3226X_PATCH_C_PBB12;
extern const proslicPatch SI3226X_PATCH_C_PBB12HV;
extern Si3226x_General_Cfg Si3226x_General_Configuration_MultiBOM[];
extern int si3226x_genconf_multi_max_preset;
#else
extern const proslicPatch SI3226X_PATCH_B_DEFAULT;
extern const proslicPatch SI3226X_PATCH_C_DEFAULT;
#endif
/* Ringing */
#ifndef DISABLE_RING_SETUP
extern Si3226x_Ring_Cfg Si3226x_Ring_Presets[];
#endif
/* Tone Generation */
#ifndef DISABLE_TONE_SETUP
extern Si3226x_Tone_Cfg Si3226x_Tone_Presets[];
#endif
/* FSK */
#ifndef DISABLE_FSK_SETUP
extern Si3226x_FSK_Cfg Si3226x_FSK_Presets[];
#endif
/* DTMF */
#ifndef DISABLE_DTMF_SETUP
extern Si3226x_DTMFDec_Cfg Si3226x_DTMFDec_Presets[];
#endif
/* Zsynth */
#ifndef DISABLE_ZSYNTH_SETUP
extern Si3226x_Impedance_Cfg Si3226x_Impedance_Presets [];
#endif
/* CI/GCI */
#ifndef DISABLE_CI_SETUP
extern Si3226x_CI_Cfg Si3226x_CI_Presets [];
#endif
/* Audio Gain Scratch */
extern Si3226x_audioGain_Cfg Si3226x_audioGain_Presets[];
/* DC Feed */
#ifndef DISABLE_DCFEED_SETUP
extern Si3226x_DCfeed_Cfg Si3226x_DCfeed_Presets[];
#endif
/* GPIO */
#ifndef DISABLE_GPIO_SETUP
extern Si3226x_GPIO_Cfg Si3226x_GPIO_Configuration ;
#endif
/* Pulse Metering */
#ifndef DISABLE_PULSE_SETUP
extern Si3226x_PulseMeter_Cfg Si3226x_PulseMeter_Presets [];
#endif
/* PCM */
#ifndef DISABLE_PCM_SETUP
extern Si3226x_PCM_Cfg Si3226x_PCM_Presets [];
#endif
/*
** Local functions are defined first
*/
/*
** Function: getChipType
**
** Description:
** Decode ID register to identify chip type
**
** Input Parameters:
** ID register value
**
** Return:
** partNumberType
*/
static partNumberType getChipType(uInt8 lsbs, uInt8 msb){
uInt8 part_num;
lsbs &= 0x38; /* PART_NUM[2:0] = ID[5:3] */
lsbs >>= 3;
msb &= 0x80; /* PART_NUM[3] = ENHANCE[7] */
msb >>= 4;
part_num = msb | lsbs;
/* Need to identify specific, supported part numbers */
if(part_num == 0x00) return(SI32260);
if(part_num == 0x04) return(SI32360);
if(part_num == 0x08) return(SI32266);
if(part_num == 0x0A) return(SI32268);
return (UNSUPPORTED_PART_NUM);
}
/*
** Function: setUserMode
**
** Description:
** Puts ProSLIC into user mode or out of user mode
**
** Input Parameters:
** pProslic: pointer to PROSLIC object
** on: specifies whether user mode should be turned on (TRUE) or off (FALSE)
**
** Return:
** none
*/
static int setUserMode (proslicChanType *pProslic,BOOLEAN on){
uInt8 data;
if (SetSemaphore != NULL){
while (!(SetSemaphore (pProHW,1)));
if (on == TRUE){
if (pProslic->deviceId->usermodeStatus<2)
pProslic->deviceId->usermodeStatus++;
} else {
if (pProslic->deviceId->usermodeStatus>0)
pProslic->deviceId->usermodeStatus--;
if (pProslic->deviceId->usermodeStatus != 0)
return -1;
}
}
data = ReadReg(pProHW,pProslic->channel,USERMODE_ENABLE);
if (((data&1) != 0) == on)
return 0;
WriteReg(pProHW,pProslic->channel,USERMODE_ENABLE,2);
WriteReg(pProHW,pProslic->channel,USERMODE_ENABLE,8);
WriteReg(pProHW,pProslic->channel,USERMODE_ENABLE,0xe);
WriteReg(pProHW,pProslic->channel,USERMODE_ENABLE,0);
if (SetSemaphore != NULL)
SetSemaphore(pProHW,0);
return 0;
}
/*
** Function: setUserModeBroadcast
**
** Description:
** Puts ProSLIC into user mode or out of user mode
**
** Input Parameters:
** pProslic: pointer to PROSLIC object
** on: specifies whether user mode should be turned on (TRUE) or off (FALSE)
**
** Return:
** none
*/
static int setUserModeBroadcast (proslicChanType *pProslic,BOOLEAN on){
uInt8 data;
if (SetSemaphore != NULL){
while (!(SetSemaphore (pProHW,1)));
if (on == TRUE){
if (pProslic->deviceId->usermodeStatus<2)
pProslic->deviceId->usermodeStatus++;
} else {
if (pProslic->deviceId->usermodeStatus>0)
pProslic->deviceId->usermodeStatus--;
if (pProslic->deviceId->usermodeStatus != 0)
return -1;
}
}
data = ReadReg(pProHW,pProslic->channel,USERMODE_ENABLE);/*we check first channel. we assume all channels same user mode state*/
if (((data&1) != 0) == on)
return 0;
WriteReg(pProHW,BROADCAST,USERMODE_ENABLE,2);
WriteReg(pProHW,BROADCAST,USERMODE_ENABLE,8);
WriteReg(pProHW,BROADCAST,USERMODE_ENABLE,0xe);
WriteReg(pProHW,BROADCAST,USERMODE_ENABLE,0);
if (SetSemaphore != NULL)
SetSemaphore(pProHW,0);
return 0;
}
/*
** Function: isVerifiedProslic
**
** Description:
** Determine if DAA or ProSLIC present
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
**
** Return:
** channelType
*/
static int identifyChannelType(proslicChanType *pProslic){
uInt8 data;
/*
** Register 13 (DAA) always has bits 0:1 set to 0 and bit 6 set to 1
** Register 13 (PROSLIC) can have bits 0:1, and 4 set, while all others are undefined
** Write 0x13 to Reg 13. The following return values are expected -
**
** 0x00 or 0xFF : No device present
** 0x4X : DAA
** 0x13 : PROSLIC
*/
WriteReg(pProHW,pProslic->channel,PCMTXHI,0x13);
data = ReadReg(pProHW,pProslic->channel,PCMTXHI); /* Active delay */
data = ReadReg(pProHW,pProslic->channel,PCMTXHI); /* Read again */
if( data == 0x13)
return PROSLIC;
else if (data == 0x40)
return DAA;
else
return UNKNOWN;
}
/*
** Function: Si3226x_EnablePatch
**
** Description:
** Enables patch
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
**
** Returns:
** 0
*/
static int Si3226x_EnablePatch (proslicChanType *pProslic){
setUserMode (pProslic,TRUE);
WriteReg (pProHW, pProslic->channel, JMPEN,1);
setUserMode (pProslic,FALSE);
return 0;
}
/*
** Function: isReinitRequired
**
** Description:
** Checks for improper ring exit
**
** Returns:
** RC_NONE - Reinit not required
** RC_REINIT_REQUIRED - Corrupted state machine - reinit required
**
*/
static int isReinitRequired(proslicChanType *pProslic)
{
uInt8 lf;
ramData rkdc_sum;
if(pProslic->channelType != PROSLIC)
{
return RC_IGNORE;
}
/* Check for improper ring exit which may cause dcfeed corruption */
lf = ReadReg(pProHW,pProslic->channel,LINEFEED);
setUserMode(pProslic,TRUE);
rkdc_sum = ReadRAM(pProHW,pProslic->channel,RDC_SUM);
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("isReinitRequired : Linefeed = %d\n", lf);
LOGPRINT("isReinitRequired : RDC_SUM = %d\n", rkdc_sum);
}
#endif
if((rkdc_sum & 0x400000)&&(!(lf & 0x44)))
{
return RC_REINIT_REQUIRED;
}
else
{
return RC_NONE;
}
}
/*
** Function: Si3226x_PowerUpConverter
**
** Description:
** Powers all DC/DC converters sequentially with delay to minimize
** peak power draw on VDC.
**
** Returns:
** int (error)
**
*/
int Si3226x_PowerUpConverter(proslicChanType_ptr pProslic)
{
errorCodeType error = RC_NONE;
int32 vbath,vbat;
uInt8 reg;
ramData data;
int timer = 0;
setUserMode(pProslic,TRUE);
/*
** Check to see if already powered, return if so
*/
data = ReadRAM(pProHW,pProslic->channel,PD_DCDC);
if(!(data & 0x100000))
{
setUserMode(pProslic,FALSE);
return error; /* Return if already powered up */
}
/*
** Power up sequence
*/
if(Si3226x_General_Configuration.batType == BO_DCDC_TRACKING)
{
/*
** TRACKING CONVERTER SEQUENCE
**
** - clear previous ov/uv lockout
** - powerup charge pump
** - delay
** - powerup digital dc/dc w/ OV clamping and shutdown
** - delay
** - verify no short circuits by looking for vbath/2
** - clear dcdc status
** - switch to analog converter with OV clamping only (no shutdown)
** - select analog dcdc and disable pwrsave
** - delay
*/
WriteRAM(pProHW,pProslic->channel,DCDC_OITHRESH,Si3226x_General_Configuration.dcdc_oithresh_lo);
WriteReg(pProHW,pProslic->channel,LINEFEED,LF_OPEN); /* Ensure open before powering converter */
reg = ReadReg(pProHW,pProslic->channel,ENHANCE); /* Read ENHANCE entry settings */
WriteReg(pProHW,pProslic->channel,ENHANCE,reg&0x07); /* Disable powersave during bringup */
WriteRAM(pProHW,pProslic->channel,PD_DCDC,0x700000L); /* In case OV or UV previously occurred */
WriteRAM(pProHW,pProslic->channel,DCDC_CPUMP,0x100000L);/* Turn on charge pump */
Delay(pProTimer,10);
WriteRAM(pProHW,pProslic->channel,PD_DCDC,0x600000L);
Delay(pProTimer,50);
vbath = ReadRAM(pProHW,pProslic->channel,VBATH_EXPECT);
vbat = ReadRAM(pProHW,pProslic->channel,MADC_VBAT);
if(vbat & 0x10000000L)
vbat |= 0xF0000000L;
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("VBAT @ 50ms = %d.%d v\n",(int)((vbat/SCALE_V_MADC)/1000), (int)(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
}
#endif
if(vbat < (vbath / 2)) {
pProslic->channelEnable = 0;
error = RC_VBAT_UP_TIMEOUT;
WriteRAM(pProHW,pProslic->channel,PD_DCDC, 0x300000L); /* shutdown converter */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Si3226x DCDC Short Circuit Failure %d - disabling channel\n",pProslic->channel);
}
#endif
setUserMode(pProslic,FALSE);
return error;
}
else { /* Enable analog converter */
WriteRAM(pProHW,pProslic->channel,DCDC_STATUS,0L);
WriteRAM(pProHW,pProslic->channel,PD_DCDC,0x400000L);
WriteReg(pProHW,pProslic->channel,ENHANCE,reg); /* restore ENHANCE setting */
Delay(pProTimer,50);
}
/*
** - monitor vbat vs expected level (VBATH_EXPECT)
*/
vbath = ReadRAM(pProHW,pProslic->channel,VBATH_EXPECT);
do
{
vbat = ReadRAM(pProHW,pProslic->channel,MADC_VBAT);
if(vbat & 0x10000000L)
vbat |= 0xF0000000L;
Delay(pProTimer,10);
}while((vbat < (vbath - COMP_5V))&&(timer++ < 200)); /* 2 sec timeout */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("VBAT Up = %d.%d v\n",(int)((vbat/SCALE_V_MADC)/1000), (int)(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
}
#endif
if(timer > 200)
{
/* Error handling - shutdown converter, disable channel, set error tag */
pProslic->channelEnable = 0;
error = RC_VBAT_UP_TIMEOUT;
WriteRAM(pProHW,pProslic->channel,PD_DCDC, 0x300000L); /* shutdown converter */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Si3226x DCDC Power up timeout channel %d - disabling channel\n",pProslic->channel);
}
#endif
}
setUserMode(pProslic,FALSE);
return error;
}
else if((Si3226x_General_Configuration.batType == BO_DCDC_TSS)||(Si3226x_General_Configuration.batType == BO_DCDC_TSS_ISO))
{
/*
** FIXED RAIL CONVERTER SEQUENCE
**
** - return if even channel
** - clear previous ov/uv lockout
** - powerup charge pump
** - delay
** - powerup converter
** - delay
** - verify no short circuits by looking for vbath/2
** - clear dcdc status
** - delay
*/
if( pProslic->channel %2 == 0) /* is even */
{
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("si3226x : DCDC Powerup Channel %d Ignored\n", pProslic->channel);
}
#endif
setUserMode(pProslic,FALSE);
return RC_IGNORE;
}
WriteRAM(pProHW,pProslic->channel,DCDC_OITHRESH,Si3226x_General_Configuration.dcdc_oithresh_lo);
WriteReg(pProHW,pProslic->channel,LINEFEED,LF_OPEN); /* Ensure open before powering converter */
reg = ReadReg(pProHW,pProslic->channel,ENHANCE); /* Read ENHANCE entry settings */
WriteReg(pProHW,pProslic->channel,ENHANCE,reg&0x07); /* Disable powersave during bringup */
WriteRAM(pProHW,pProslic->channel,PD_DCDC,0x700000L); /* In case OV or UV previously occurred */
/* Do not turn on charge pump if isolated design */
if(Si3226x_General_Configuration.batType != BO_DCDC_TSS_ISO)
{
WriteRAM(pProHW,pProslic->channel,DCDC_CPUMP,0x100000L);/* Turn on charge pump */
}
Delay(pProTimer,10);
WriteRAM(pProHW,pProslic->channel,PD_DCDC,0x600000L);
Delay(pProTimer,500);
vbath = ReadRAM(pProHW,pProslic->channel,VBATH_EXPECT);
vbat = ReadRAM(pProHW,pProslic->channel,MADC_VBAT);
if(vbat & 0x10000000L)
vbat |= 0xF0000000L;
if(vbath & 0x10000000L)
vbath |= 0xF0000000L;
LOGPRINT ("Initial VBAT = %d.%d v\n",(int)((vbat/SCALE_V_MADC)/1000), (int)(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
if(vbat < (vbath / 2)) {
pProslic->channelEnable = 0;
error = RC_VBAT_UP_TIMEOUT;
WriteRAM(pProHW,pProslic->channel,PD_DCDC, 0x300000L); /* shutdown converter */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Si3226x DCDC Short Circuit Failure %d - disabling channel\n",pProslic->channel);
}
#endif
setUserMode(pProslic,FALSE);
return error;
}
else {
WriteRAM(pProHW,pProslic->channel,DCDC_STATUS,0L);
Delay(pProTimer,50);
}
/*
** - monitor vbat vs expected level (VBATH_EXPECT)
*/
vbath = ReadRAM(pProHW,pProslic->channel,VBATH_EXPECT);
do
{
vbat = ReadRAM(pProHW,pProslic->channel,MADC_VBAT);
if(vbat & 0x10000000L)
vbat |= 0xF0000000L;
Delay(pProTimer,10);
}while((vbat < (vbath - COMP_5V))&&(timer++ < 200)); /* 2 sec timeout */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Fixed VBAT Up = %d.%d v\n",(int)((vbat/SCALE_V_MADC)/1000), (int)(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
}
#endif
if(timer > 200)
{
/* Error handling - shutdown converter, disable channel, set error tag */
pProslic->channelEnable = 0;
error = RC_VBAT_UP_TIMEOUT;
WriteRAM(pProHW,pProslic->channel,PD_DCDC, 0x300000L); /* shutdown converter */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Si3226x DCDC Fixed Rail Power up timeout channel %d - disabling channel\n",pProslic->channel);
}
#endif
}
/* Restore ENHANCE reg */
WriteReg(pProHW,pProslic->channel,ENHANCE,reg);
setUserMode(pProslic,FALSE);
return error;
}
else /* external battery - just verify presence */
{
/*
** - monitor vbat vs expected level (VBATH_EXPECT)
*/
vbath = ReadRAM(pProHW,pProslic->channel,VBATH_EXPECT);
do
{
vbat = ReadRAM(pProHW,pProslic->channel,MADC_VBAT);
if(vbat & 0x10000000L)
vbat |= 0xF0000000L;
Delay(pProTimer,10);
}while((vbat < (vbath - COMP_5V))&&(timer++ < 200)); /* 2 sec timeout */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Ext VBAT Up = %d.%d v\n",(int)((vbat/SCALE_V_MADC)/1000), (int)(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
}
#endif
if(timer > 200)
{
/* Error handling - shutdown converter, disable channel, set error tag */
pProslic->channelEnable = 0;
error = RC_VBAT_UP_TIMEOUT;
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Si3226x External VBAT timeout channel %d - disabling channel\n",pProslic->channel);
}
#endif
}
}
setUserMode(pProslic,FALSE);
return error;
}
/*
** Function: Si3226x_PowerDownConverter
**
** Description:
** Safely powerdown dcdc converter after ensuring linefeed
** is in the open state. Test powerdown by setting error
** flag if detected voltage does no fall below 5v.
**
** Returns:
** int (error)
**
*/
int Si3226x_PowerDownConverter(proslicChanType_ptr pProslic)
{
errorCodeType error = RC_NONE;
int32 vbat;
int timer = 0;
ramData data;
setUserMode(pProslic,TRUE);
/*
** Check to see if already powered down, return if so
*/
data = ReadRAM(pProHW,pProslic->channel,PD_DCDC);
if((data & 0x100000))
{
setUserMode(pProslic,FALSE);
return error; /* Return if already powered down */
}
/*
** Power down sequence */
WriteReg(pProHW,pProslic->channel,LINEFEED,LF_FWD_OHT); /* Force out of powersave mode */
WriteReg(pProHW,pProslic->channel,LINEFEED, LF_OPEN);
Delay(pProTimer,50);
WriteRAM(pProHW,pProslic->channel,PD_DCDC,0x900000L);
Delay(pProTimer,50);
/*
** Verify VBAT falls below 5v
*/
do
{
vbat = ReadRAM(pProHW,pProslic->channel,MADC_VBAT);
if(vbat & 0x10000000L)
vbat |= 0xF0000000L;
Delay(pProTimer,10);
}while((vbat > COMP_5V)&&(timer++ < SI3226X_TIMEOUT_DCDC_DOWN)); /* 200 msec timeout */
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("VBAT Down = %d.%d v\n",(int)((vbat/SCALE_V_MADC)/1000), (int)(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
}
#endif
if(timer > SI3226X_TIMEOUT_DCDC_DOWN)
{
/* Error handling - shutdown converter, disable channel, set error tag */
pProslic->channelEnable = 0;
error = RC_VBAT_DOWN_TIMEOUT;
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT ("Si3226x DCDC Power Down timeout channel %d\n",pProslic->channel);
}
#endif
}
setUserMode(pProslic,FALSE);
return error;
}
/* Old cal left in for now until we clear up forward decs */
int Si3226x_Cal(proslicChanType_ptr *pProslic, int maxChan)
{
return 0;
}
/*
** Function: Si3226x_Calibrate
**
** Description:
** Performs calibration based on passed ptr to array of
** desired CALRn settings.
**
** Starts calibration on all channels sequentially (not broadcast)
** and continuously polls for completion. Return error code if
** CAL_EN does not clear for each enabled channel within the passed
** timeout period.
*/
int Si3226x_Calibrate(proslicChanType_ptr *pProslic, int maxChan, uInt8 *calr, int maxTime)
{
int i;
int cal_en = 0;
int cal_en_chan = 0;
int timer = 0;
/*
** Launch cals sequentially (not serially)
*/
for(i=0;i<maxChan;i++)
{
if((pProslic[i]->channelEnable)&&(pProslic[i]->channelType == PROSLIC))
{
pProslic[i]->WriteRegX(pProslic[i]->pProHWX,pProslic[i]->channel,CALR0,calr[0]);
pProslic[i]->WriteRegX(pProslic[i]->pProHWX,pProslic[i]->channel,CALR1,calr[1]);
pProslic[i]->WriteRegX(pProslic[i]->pProHWX,pProslic[i]->channel,CALR2,calr[2]);
pProslic[i]->WriteRegX(pProslic[i]->pProHWX,pProslic[i]->channel,CALR3,calr[3]);
}
}
/*
** Wait for completion or timeout
*/
do
{
cal_en = 0;
pProslic[0]->DelayX(pProslic[0]->pProTimerX,10);
for(i=0;i<maxChan;i++)
{
if(pProslic[i]->channelEnable)
{
cal_en_chan = pProslic[i]->ReadRegX(pProslic[i]->pProHWX,pProslic[i]->channel,CALR3);
if((cal_en_chan&0x80)&&(timer == maxTime))
{
#ifdef ENABLE_DEBUG
if(pProslic[i]->debugMode)
{
LOGPRINT("Calibration timout channel %d\n",i);
}
#endif
pProslic[i]->channelEnable = 0;
pProslic[i]->error = RC_CAL_TIMEOUT;
}
cal_en |= cal_en_chan;
}
}
}while((timer++ <= maxTime)&&(cal_en&0x80));
return cal_en;
}
/*
** Function: LoadRegTables
**
** Description:
** Generic function to load register/RAM with predefined addr/value
*/
static int LoadRegTables (proslicChanType *pProslic, ProslicRAMInit *pRamTable, ProslicRegInit *pRegTable, int broadcast){
uInt16 i;
uInt8 channel;
if (broadcast){
channel = BROADCAST;
setUserModeBroadcast(pProslic,TRUE);
}
else {
channel = pProslic->channel;
setUserMode(pProslic,TRUE);
}
i=0;
if (pRamTable != 0){
while (pRamTable[i].address != 0xffff){
WriteRAM(pProHW,channel,pRamTable[i].address,pRamTable[i].initValue);
i++;
}
}
i=0;
if (pRegTable != 0){
while (pRegTable[i].address != 0xff){
WriteReg(pProHW,channel,pRegTable[i].address,pRegTable[i].initValue);
i++;
}
}
if (broadcast)
setUserModeBroadcast(pProslic,FALSE);
else
setUserMode(pProslic,FALSE);
return 0;
}
/*
** Function: LoadSi3226xPatch
**
** Description:
** Load patch from external file defined as 'RevBPatch'
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
** broadcast: broadcast flag
**
** Return:
** 0
*/
static int LoadSi3226xPatch (proslicChanType *pProslic, const proslicPatch *pPatch,int broadcast){
int32 loop;
uInt8 jmp_table_low = PATCH_JMPTBL_LOW_ADDR;
uInt16 jmp_table_high = PATCH_JMPTBL_HIGH_ADDR;
uInt8 channel;
ramData data;
if (pPatch == NULL)
return 0;
if (broadcast){
setUserModeBroadcast(pProslic,TRUE);
channel = BROADCAST;
}
else{
setUserMode (pProslic,TRUE); /*make sure we are in user mode to load patch*/
channel = pProslic->channel;
}
/* Disable patch */
WriteReg (pProHW, pProslic->channel, JMPEN,0);
/**
* Zero out jump table(s) in case previous values are still loaded
*/
for (loop=0;loop<PATCH_NUM_LOW_ENTRIES;loop++){
/*zero out the jump table*/
WriteReg (pProHW, channel, jmp_table_low,0);
WriteReg (pProHW, channel, jmp_table_low+1,0);
jmp_table_low+=2;
}
for (loop=0;loop<PATCH_NUM_HIGH_ENTRIES;loop++){
/*zero out the jump table*/
WriteRAM (pProHW, channel, jmp_table_high,0L);
jmp_table_high++;
}
/**
* Load patch RAM data
*/
WriteRAM(pProHW, channel,PRAM_ADDR, 0); /*write patch ram address register
If the data is all 0, you have hit the end of the programmed values and can stop loading.*/
for (loop=0; loop<PATCH_MAX_SIZE; loop++){
if (pPatch->patchData[loop] != 0){
if ((pProslic->deviceId->chipRev < 3) && broadcast)
WriteRAM(pProHW, channel,PRAM_ADDR, loop<<19); /*write patch ram address register (only necessary for broadcast rev c and earlier)*/
WriteRAM(pProHW, channel,PRAM_DATA,pPatch->patchData[loop]<<9); /*loading patch, note. data is shifted*/
}
else
loop = 1024;
}
/* Delay 1 mSec to ensure last RAM write completed - this should be quicker than doing a SPI access
to confirm the status register.
*/
Delay(pProTimer, 1);
/*zero out RAM_ADDR_HI*/
WriteReg (pProHW, channel, RAM_ADDR_HI,0);
/**
* Lower 8 Jump Table Entries - register space
*/
jmp_table_low=PATCH_JMPTBL_LOW_ADDR;
for (loop=0;loop<PATCH_NUM_LOW_ENTRIES;loop++){
/* Load the jump table with the new values.*/
if (pPatch->patchEntries[loop] != 0){
WriteReg (pProHW, channel, jmp_table_low,(pPatch->patchEntries[loop])&0xff);
WriteReg (pProHW, channel, jmp_table_low+1,pPatch->patchEntries[loop]>>8);
}
jmp_table_low+=2;
}
/**
* Upper 8 Jump Table Entries - Memory Mapped register space
*/
jmp_table_high=PATCH_JMPTBL_HIGH_ADDR;
for (loop=0;loop<PATCH_NUM_HIGH_ENTRIES;loop++){
if (pPatch->patchEntries[loop] != 0)
{
data = ((uInt32) (pPatch->patchEntries[loop+PATCH_NUM_LOW_ENTRIES])) & 0x00001fffL ;
WriteRAM (pProHW, channel, jmp_table_high, data );
}
jmp_table_high++;
}
WriteRAM(pProHW,channel,PATCH_ID,pPatch->patchSerial); /*write patch identifier*/
/**
* Write patch support RAM locations (if any)
*/
for (loop=0; loop<PATCH_MAX_SUPPORT_RAM; loop++){
if(pPatch->psRamAddr[loop] != 0) {
WriteRAM(pProHW,channel,pPatch->psRamAddr[loop],pPatch->psRamData[loop]);
}
else {
loop = PATCH_MAX_SUPPORT_RAM;
}
}
if (broadcast){
setUserModeBroadcast(pProslic,FALSE);
}
else {
setUserMode(pProslic,FALSE); /*turn off user mode*/
}
return 0;
}
/*
** Functions below are defined in header file and can be called by external files
*/
/*
**
** PROSLIC INITIALIZATION FUNCTIONS
**
*/
/*
** Function: PROSLIC_Reset
**
** Description:
** Resets the ProSLIC
*/
int Si3226x_Reset (proslicChanType_ptr pProslic){
/*
** resets ProSLIC, wait 250ms, release reset, wait 250ms
*/
Reset(pProHW,1);
Delay(pProTimer,250);
Reset(pProHW,0);
Delay(pProTimer,250);
return 0;
}
/*
** Function: Si3226x_ShutdownChannel
**
** Description:
** Safely shutdown channel w/o interruptions to
** other active channels
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
**
** Return:
** 0
*/
int Si3226x_ShutdownChannel (proslicChanType_ptr pProslic){
uInt8 reg;
int error = 0;
/*
** set linefeed to open state, powerdown dcdc converter
*/
reg = ReadReg(pProHW,pProslic->channel,LINEFEED);
if(reg != 0)
Si3226x_SetLinefeedStatus(pProslic,LF_FWD_OHT); /* force low power mode exit */
Si3226x_SetLinefeedStatus(pProslic,LF_OPEN);
Delay(pProTimer,10);
/*
** Shutdown converter if not using external supply.
*/
if(Si3226x_General_Configuration.batType != BO_DCDC_EXTERNAL)
error = Si3226x_PowerDownConverter(pProslic);
return error;
}
/*
** Function: Si3226x_VerifyControlInterface
**
** Description:
** Check control interface readback cababilities
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
**
** Return:
** 0
*/
int Si3226x_VerifyControlInterface (proslicChanType_ptr pProslic)
{
if (identifyChannelType(pProslic) != PROSLIC)
return RC_CHANNEL_TYPE_ERR;
WriteReg (pProHW,pProslic->channel,PCMRXLO,0x5A);
if (ReadReg(pProHW,pProslic->channel,PCMRXLO) != 0x5A){
pProslic->error = RC_SPI_FAIL;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x: Proslic %d registers not communicating.\n",pProslic->channel);
#endif
return RC_SPI_FAIL;
}
/* Verify RAM rd/wr with innocuous RAM location */
WriteRAM(pProHW,pProslic->channel,UNUSED449,0x12345678L);
if (ReadRAM(pProHW,pProslic->channel, UNUSED449) != 0x12345678L){
pProslic->error = RC_SPI_FAIL;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x: Proslic %d RAM not communicating. RAM access fail.\n",pProslic->channel);
#endif
return RC_SPI_FAIL;
}
return RC_NONE;
}
/*
** Function: Si3226x_Init_MultiBOM
**
** Description:
** - probe SPI to establish daisy chain length
** - load patch
** - initialize general parameters
** - calibrate madc
** - bring up DC/DC converters
** - calibrate remaining items except madc & lb
**
** Input Parameters:
** pProslic: pointer to PROSLIC object array
** fault: error code
**
** Return:
** error code
*/
#ifdef SIVOICE_MULTI_BOM_SUPPORT
int Si3226x_Init_MultiBOM(proslicChanType_ptr *pProslic,int size, int preset) {
if(preset < si3226x_genconf_multi_max_preset)
{
/* Copy selected General COnfiguration parameters to std structure */
Si3226x_General_Configuration = Si3226x_General_Configuration_MultiBOM[preset];
}
else
{
return RC_INVALID_PRESET;
}
return Si3226x_Init(pProslic,size);
}
#endif
/*
** Function: Si3226x_Init_with_Options
**
** Description:
** - probe SPI to establish daisy chain length
** - load patch
** - initialize general parameters
** - calibrate madc
** - bring up DC/DC converters
** - calibrate remaining items except madc & lb
**
** Input Parameters:
** pProslic: pointer to PROSLIC object array
** fault: error code
**
** Return:
** error code
*/
static int Si3226x_Init_with_Options (proslicChanType_ptr *pProslic, int size, initOptionsType init_opt){
/*
** This function will initialize the chipRev and chipType members in pProslic
** as well as load the initialization structures.
*/
uInt8 data,id,enhance;
uInt8 calSetup[] = {0x00, 0x00, 0x01, 0x80}; /* CALR0-CALR3 */
int k;
const proslicPatch *patch = NULL;
/* Skip part identification and patch load steps if reinitializing */
if(init_opt != INIT_REINIT)
{
/*
** Identify channel type (ProSLIC or DAA) before initialization.
** Channels identified as DAA channels will not be modified during
** the ProSLIC initialization
*/
for (k=0;k<size;k++)
{
pProslic[k]->channelType = identifyChannelType(pProslic[k]);
#ifdef ENABLE_DEBUG
if(pProslic[k]->debugMode)
{
if(pProslic[k]->channelType == PROSLIC)
LOGPRINT("si3226x : Channel %d : Type = PROSLIC\n",pProslic[k]->channel);
else if(pProslic[k]->channelType == DAA)
LOGPRINT("si3226x : Channel %d : Type = DAA\n",pProslic[k]->channel);
else
LOGPRINT("si3226x : Channel %d : Type = UNKNOWN\n",pProslic[k]->channel);
}
#endif
}
/*
** Read channel id to establish chipRev and chipType
*/
for (k=0;k<size;k++)
{
if(pProslic[k]->channelType == PROSLIC)
{
id = pProslic[k]->ReadRegX(pProslic[k]->pProHWX,pProslic[k]->channel,ID);
enhance = pProslic[k]->ReadRegX(pProslic[k]->pProHWX,pProslic[k]->channel,ENHANCE);
pProslic[k]->deviceId->chipRev = id&0x7;
pProslic[k]->deviceId->chipType = getChipType(id,enhance);
#ifdef ENABLE_DEBUG
if(pProslic[k]->debugMode)
{
LOGPRINT("si3226x : Channel %d : Chip Type %d\n",pProslic[k]->channel,pProslic[k]->deviceId->chipType);
LOGPRINT("si3226x : Channel %d : Chip Rev %d\n",pProslic[k]->channel,pProslic[k]->deviceId->chipRev);
}
#endif
}
}
/*
** Probe each channel and enable all channels that respond
*/
for (k=0;k<size;k++){
if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC)){
pProslic[k]->WriteRegX(pProslic[k]->pProHWX,pProslic[k]->channel,PCMRXLO,0x5a);
if (pProslic[k]->ReadRegX(pProslic[k]->pProHWX,pProslic[k]->channel,PCMRXLO) != 0x5A){
pProslic[k]->channelEnable = 0;
pProslic[k]->error = RC_SPI_FAIL;
return pProslic[k]->error; /* Halt init if SPI fail */
}
}
}
} /* init_opt */
if((init_opt != INIT_REINIT)&&(init_opt != INIT_NO_PATCH_LOAD))
{
/**
* Load patch (do not enable until patch loaded on all channels)
*/
for (k=0;k<size;k++)
{
if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC))
{
if (pProslic[k]->deviceId->chipRev == SI3226X_REVB )
{
#ifdef SIVOICE_MULTI_BOM_SUPPORT
if(Si3226x_General_Configuration.bomOpt == BO_DCDC_FLYBACK)
{
if(Si3226x_General_Configuration.batType == BO_DCDC_TRACKING)
{
patch = &(SI3226X_PATCH_B_FLBK);
}
else
{
patch = &(SI3226X_PATCH_B_FIXRL);
}
}
else
{
#ifdef ENABLE_DEBUG
if(pProslic[k]->debugMode)
{
LOGPRINT("si3226x : Channel %d : Invalid Patch\n",pProslic[k]->channel);
}
#endif
pProslic[k]->channelEnable = 0;
pProslic[k]->error = RC_INVALID_PATCH;
return RC_INVALID_PATCH;
}
#else
patch = &(SI3226X_PATCH_B_DEFAULT);
#endif
}
else if (pProslic[k]->deviceId->chipRev == SI3226X_REVC )
{
#ifdef SIVOICE_MULTI_BOM_SUPPORT
if(Si3226x_General_Configuration.batType == BO_DCDC_TRACKING)
{
if(Si3226x_General_Configuration.bomOpt == BO_DCDC_FLYBACK)
{
patch = &(SI3226X_PATCH_C_FLBK);
}
else if(Si3226x_General_Configuration.bomOpt == BO_DCDC_QCUK)
{
patch = &(SI3226X_PATCH_C_QCUK);
}
else if(Si3226x_General_Configuration.bomOpt == BO_DCDC_LCQCUK)
{
patch = &(SI3226X_PATCH_C_LCQCUK);
}
else if(Si3226x_General_Configuration.bomOpt == BO_DCDC_CUK)
{
patch = &(SI3226X_PATCH_C_CUK);
}
else if(Si3226x_General_Configuration.bomOpt == BO_DCDC_P_BUCK_BOOST_5V)
{
patch = &(SI3226X_PATCH_C_PBB5);
}
else if(Si3226x_General_Configuration.bomOpt == BO_DCDC_P_BUCK_BOOST_12V)
{
patch = &(SI3226X_PATCH_C_PBB12);
}
else if(Si3226x_General_Configuration.bomOpt == BO_DCDC_P_BUCK_BOOST_12V_HV)
{
patch = &(SI3226X_PATCH_C_PBB12HV);
}
}
else if((Si3226x_General_Configuration.batType == BO_DCDC_TSS)&&(Si3226x_General_Configuration.bomOpt == BO_DCDC_FLYBACK))
{
patch = &(SI3226X_PATCH_C_TSS);
}
else if((Si3226x_General_Configuration.batType == BO_DCDC_TSS_ISO)&&(Si3226x_General_Configuration.bomOpt == BO_DCDC_FLYBACK))
{
patch = &(SI3226X_PATCH_C_TSS_ISO);
}
else
{
#ifdef ENABLE_DEBUG
if(pProslic[k]->debugMode)
{
LOGPRINT("si3226x : Channel %d : Invalid Patch\n",pProslic[k]->channel);
}
#endif
pProslic[k]->channelEnable = 0;
pProslic[k]->error = RC_INVALID_PATCH;
return RC_INVALID_PATCH;
}
#else
patch = &(SI3226X_PATCH_C_DEFAULT);
#endif
}
else
{
#ifdef ENABLE_DEBUG
if (pProslic[k]->debugMode)
{
LOGPRINT("si3226x : Channel %d : Unsupported Device Revision (%d)\n",pProslic[k]->channel,pProslic[k]->deviceId->chipRev );
}
#endif
pProslic[k]->channelEnable = 0;
pProslic[k]->error = RC_UNSUPPORTED_DEVICE_REV;
return RC_UNSUPPORTED_DEVICE_REV;
}
Si3226x_LoadPatch(pProslic[k],patch);
}
}
/**
* Verify and Enable Patch
*/
for (k=0;k<size;k++)
{
if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC))
{
#ifdef DISABLE_VERIFY_PATCH
Si3226x_EnablePatch(pProslic[k]);
#else
data = Si3226x_VerifyPatch(pProslic[k],patch);
if (data)
{
pProslic[k]->channelEnable=0;
pProslic[k]->error = data;
return data; /* Stop Init if patch load failure occurs */
}
else
{
Si3226x_EnablePatch(pProslic[k]);
}
#endif
}
}
} /* init_opt */
/*
** Load general parameters - includes all BOM dependencies
**
** First qualify general parameters by identifying valid device key. This
** will prevent inadvertent use of other device's preset files, which could
** lead to improper initialization and high current states.
*/
data = Si3226x_General_Configuration.device_key;
if((data < DEVICE_KEY_MIN)||(data > DEVICE_KEY_MAX))
{
pProslic[0]->error = RC_INVALID_GEN_PARAM;
return pProslic[0]->error;
}
for (k=0;k<size;k++){
if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC)){
setUserMode(pProslic[k],TRUE);
/* Force pwrsave off and disable AUTO-tracking - set to user configured state after cal */
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,ENHANCE,0);
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,AUTO,0x2F);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,BAT_HYST,Si3226x_General_Configuration.bat_hyst);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VBATR_EXPECT,Si3226x_General_Configuration.vbatr_expect);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VBATH_EXPECT,Si3226x_General_Configuration.vbath_expect);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,PWRSAVE_TIMER,Si3226x_General_Configuration.pwrsave_timer);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,OFFHOOK_THRESH,Si3226x_General_Configuration.offhook_thresh);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VBAT_TRACK_MIN,Si3226x_General_Configuration.vbat_track_min);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VBAT_TRACK_MIN_RNG,Si3226x_General_Configuration.vbat_track_min_rng);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,THERM_DBI,Si3226x_General_Configuration.therm_dbi);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_VERR,Si3226x_General_Configuration.dcdc_verr);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_VERR_HYST,Si3226x_General_Configuration.dcdc_verr_hyst);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_OITHRESH_LO,Si3226x_General_Configuration.dcdc_oithresh_lo);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_OITHRESH_HI,Si3226x_General_Configuration.dcdc_oithresh_hi);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,PD_UVLO,Si3226x_General_Configuration.pd_uvlo);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,PD_OVLO,Si3226x_General_Configuration.pd_ovlo);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,PD_OCLO,Si3226x_General_Configuration.pd_oclo);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_UVHYST,Si3226x_General_Configuration.dcdc_uvhyst);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_UVTHRESH,Si3226x_General_Configuration.dcdc_uvthresh);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_OVTHRESH,Si3226x_General_Configuration.dcdc_ovthresh);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_SWDRV_POL,Si3226x_General_Configuration.dcdc_swdrv_pol);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_UVPOL,Si3226x_General_Configuration.dcdc_uvpol);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_VREF_CTRL,Si3226x_General_Configuration.dcdc_vref_ctrl);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_RNGTYPE,Si3226x_General_Configuration.dcdc_rngtype);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_ANA_GAIN,Si3226x_General_Configuration.dcdc_ana_gain);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_ANA_TOFF,Si3226x_General_Configuration.dcdc_ana_toff);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_ANA_TONMIN,Si3226x_General_Configuration.dcdc_ana_tonmin);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_ANA_TONMAX,Si3226x_General_Configuration.dcdc_ana_tonmax);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_ANA_DSHIFT,Si3226x_General_Configuration.dcdc_ana_dshift);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_ANA_LPOLY,Si3226x_General_Configuration.dcdc_ana_lpoly);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,COEF_P_HVIC,Si3226x_General_Configuration.coef_p_hvic);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,P_TH_HVIC,Si3226x_General_Configuration.p_th_hvic);
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,CM_CLAMP,Si3226x_General_Configuration.cm_clamp);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,SCALE_KAUDIO,Si3226x_General_Configuration.scale_kaudio);
/* GC RAM locations that moved from RevB to RevC */
if(pProslic[k]->deviceId->chipRev == SI3226X_REVB)
{
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LKG_OFHK_OFFSET_REVB,Si3226x_General_Configuration.lkg_ofhk_offset);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LKG_LB_OFFSET_REVB,Si3226x_General_Configuration.lkg_lb_offset);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VBATH_DELTA_REVB,Si3226x_General_Configuration.vbath_delta);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,UVTHRESH_MAX_REVB,Si3226x_General_Configuration.uvthresh_max);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,UVTHRESH_SCALE_REVB,Si3226x_General_Configuration.uvthresh_scale);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,UVTHRESH_BIAS_REVB,Si3226x_General_Configuration.uvthresh_bias);
}
else
{
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LKG_OFHK_OFFSET,Si3226x_General_Configuration.lkg_ofhk_offset);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LKG_LB_OFFSET,Si3226x_General_Configuration.lkg_lb_offset);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VBATH_DELTA,Si3226x_General_Configuration.vbath_delta);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,UVTHRESH_MAX,Si3226x_General_Configuration.uvthresh_max);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,UVTHRESH_SCALE,Si3226x_General_Configuration.uvthresh_scale);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,UVTHRESH_BIAS,Si3226x_General_Configuration.uvthresh_bias);
}
/* Hardcoded mods to default settings */
data = pProslic[k]->ReadRegX(pProslic[k]->pProHWX, pProslic[k]->channel,GPIO_CFG1);
data &= 0xF9; /* Clear DIR for GPIO 1&2 */
data |= 0x60; /* Set ANA mode for GPIO 1&2 */
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,GPIO_CFG1,data); /* coarse sensors analog mode */
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,PDN,0x80); /* madc powered in open state */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,TXACHPF_A1_1,0x71EB851L); /* Fix HPF corner */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,ROW0_C2, 0x723F235L); /* improved DTMF det */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,ROW1_C2, 0x57A9804L); /* improved DTMF det */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,XTALK_TIMER,0x36000L); /* xtalk fix */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_CPUMP_LP_MASK,0x1100000L); /* Charge pump mask */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VOV_DCDC_SLOPE,0xFFFFFFL); /* dcdc overhead slope */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VOV_RING_BAT_MAX,0xE49BA5L); /* max ring overhead */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VDIFFLPF,0x10038DL); /* vloop lpf 10hz */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,ILOOPLPF,0x4EDDB9L); /* iloop lpf*/
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,ILONGLPF,0x806D6L); /* ilong lpf */
/* Hardcoded mods for Tracking supplies */
if(Si3226x_General_Configuration.batType == BO_DCDC_TRACKING)
{
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_UV_DEBOUNCE, 0x200000L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_OV_DEBOUNCE, 0x0L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_OIMASK, 0xC00000L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VCM_HYST,0x206280L); /* 2v */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LPR_SCALE,0x1F00000L);/* scale for LPR amplitude */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LPR_CM_OS,0x51EB80L); /* LPR cm offset */
}
else
{
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_UV_DEBOUNCE, 0x0L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_OV_DEBOUNCE, 0xD00000L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_OIMASK, 0xA00000L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VCM_HYST,0x306280L); /* 3v */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,VBATL_EXPECT, 0xF00000L); /* force vbatl 13v to keep cm recalc */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,MADC_VDC_SCALE, 0xAE924B9L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,DCDC_PD_ANA, 0x300000);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,P_TH_OFFLOAD, 0x280CBFL); /* 1.1W @ 60C */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,PD_OFFLD_DAC,0x200000L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,PD_OFFLD_GM,0x200000L);
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LPR_SCALE,0x2A00000L);/* scale for LPR amplitude */
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,LPR_CM_OS,0x61EB80L); /* LPR cm offset */
/* Setup power offloading for tracking switched supplies */
if((Si3226x_General_Configuration.batType == BO_DCDC_TSS)||(Si3226x_General_Configuration.batType == BO_DCDC_TSS_ISO))
{
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,OFFLOAD,0x3); /* Enable offload and vbat_l */
}
else
{
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,OFFLOAD,0x13); /* Enable offload and vbat_l, disable fixed rail battery management. */
}
if(pProslic[k]->deviceId->chipRev == SI3226X_REVB)
{
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,BAT_HYST,0xAC480L);
}
}
setUserMode(pProslic[k],FALSE);
}
}
if((init_opt != INIT_NO_CAL)&&(init_opt != INIT_REINIT))
{
/*
** Calibrate (madc offset)
*/
Si3226x_Calibrate(pProslic,size,calSetup,TIMEOUT_MADC_CAL);
}
/*
** Bring up DC/DC converters sequentially to minimize
** peak power demand on VDC
*/
for (k=0;k<size;k++)
{
if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC))
{
setUserMode(pProslic[k],TRUE);
pProslic[k]->error = Si3226x_PowerUpConverter(pProslic[k]);
setUserMode(pProslic[k],FALSE);
}
}
if((init_opt != INIT_NO_CAL)&&(init_opt != INIT_REINIT))
{
/*
** Calibrate remaining cals (except madc, lb)
*/
calSetup[1] = SI3226X_CAL_STD_CALR1;
calSetup[2] = SI3226X_CAL_STD_CALR2;
Si3226x_Calibrate(pProslic,size,calSetup,TIMEOUT_GEN_CAL);
}
/*
** Apply user configured ENHANCE and AUTO
*/
for (k=0;k<size;k++){
if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC)){
setUserMode(pProslic[k],TRUE);
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,ENHANCE,Si3226x_General_Configuration.enhance);
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,AUTO,Si3226x_General_Configuration.autoRegister);
pProslic[k]->WriteRegX(pProslic[k]->pProHWX, pProslic[k]->channel,ZCAL_EN,Si3226x_General_Configuration.zcal_en);
/* Rev A Workarounds - done after cal */
if (pProslic[k]->deviceId->chipRev == SI3226X_REVA ) {
pProslic[k]->WriteRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,PD_HVIC,0x200000L); /* HVIC timing issue */
}
setUserMode(pProslic[k],FALSE);
}
}
return 0;
}
/*
** Function: Si3226x_Init
**
** Description:
** - probe SPI to establish daisy chain length
** - load patch
** - initialize general parameters
** - calibrate madc
** - bring up DC/DC converters
** - calibrate remaining items except madc & lb
**
** Input Parameters:
** pProslic: pointer to PROSLIC object array
** fault: error code
**
** Return:
** error code
*/
int Si3226x_Init (proslicChanType_ptr *pProslic, int size){
return Si3226x_Init_with_Options(pProslic,size,INIT_NO_OPT);
}
/*
** Function: Si3226x_Reinit
**
** Description:
** Performs soft reset then calls Si3226x_Init
**
** Input Parameters:
** pProslic: pointer to PROSLIC object array
** fault: error code
**
** Return:
** error code
*/
int Si3226x_Reinit (proslicChanType_ptr pProslic, int size){
uInt8 lf;
int retVal;
int reinit = 1;
int num_reinit_chan = 1;
lf = ReadReg(pProHW,pProslic->channel,LINEFEED);
Si3226x_PowerDownConverter(pProslic);
Delay(pProTimer,10);
/* Determine which soft reset to assert (dual device) */
if((pProslic->channel % 2) == 0) /* Even */
{
WriteReg(pProHW,pProslic->channel,RESET,0x01); /* device ch 0 */
}
else
{
WriteReg(pProHW,pProslic->channel,RESET,0x02); /* device ch 1 */
}
Delay(pProTimer,100);
retVal = Si3226x_Init_with_Options(&pProslic,num_reinit_chan,INIT_REINIT);
/*
** Restore entry linefeed state - if alarm occured, this
** is likely to be the OPEN state, but this function should
** be useful for all usage cases.
*/
WriteReg(pProHW,pProslic->channel,LINEFEED,lf);
return (retVal);
}
/*
** Function: Si3226x_PrintDebugReg
**
** Description:
** Register dump utility
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
**
** Return:
** 0
*/
int Si3226x_PrintDebugReg (proslicChanType *pProslic){
#ifdef ENABLE_DEBUG
int i;
for (i=0;i<99;i++)
{
LOGPRINT ("Si3226x Register %d = %X\n",i,ReadReg(pProHW,pProslic->channel,i));
}
#endif
return 0;
}
/*
** Function: Si3226x_PrintDebugRAM
**
** Description:
** Register dump utility
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
**
** Return:
** 0
*/
int Si3226x_PrintDebugRAM (proslicChanType *pProslic){
#ifdef ENABLE_DEBUG
int i;
for (i=0;i<1024;i++)
{
LOGPRINT ("Si3226x RAM %d = %X\n",i,(unsigned int)(ReadRAM(pProHW,pProslic->channel,i)));
}
#endif
return 0;
}
/*
** Function: Si3226x_PrintDebugData
**
** Description:
** Register and RAM dump utility
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
** broadcast: broadcast flag
**
** Return:
** 0
*/
int Si3226x_PrintDebugData (proslicChanType *pProslic){
Si3226x_PrintDebugReg (pProslic);
Si3226x_PrintDebugRAM (pProslic);
return 0;
}
/*
** Function: Si3226x_LBCal
**
** Description:
** Run canned longitudinal balance calibration. Each channel
** may be calibrated in parallel since there are no shared
** resources between si3226x devices.
**
** Input Parameters:
** pProslic: pointer to array of PROSLIC channel objects
** size: number of PROSLIC channel objects
**
** Return:
** 0
*/
int Si3226x_LBCal(proslicChanType_ptr *pProslic, int size)
{
int k;
int i;
uInt8 data;
int timeout = 0;
#ifdef DISABLE_MALLOC
uInt8 lf[64];
if (size > 64) {
LOGPRINT("Too many channels - wanted %d, max of %d\n",
size, 64);
return RC_NO_MEM;
}
#else
uInt8 *lf;
lf = malloc(size * sizeof(uInt8));
if (lf == 0) {
return RC_NO_MEM;
}
#endif
/* Start Cal on each channel first */
for (k=0;k<size;k++)
{
if (pProslic[k]->channelEnable)
{
#ifdef ENABLE_DEBUG
if(pProslic[k]->debugMode)
{
LOGPRINT("Starting LB Cal on channel %d\n",
pProslic[k]->channel);
}
#endif
lf[k] = pProslic[k]->ReadRegX(pProslic[k]->pProHWX,
pProslic[k]->channel,
LINEFEED);
Si3226x_SetLinefeedStatus(pProslic[k],
LF_FWD_ACTIVE);
pProslic[k]->WriteRegX(pProslic[k]->pProHWX,
pProslic[k]->channel,
CALR0,
CAL_LB_ALL); /* enable LB cal */
pProslic[k]->WriteRegX(pProslic[k]->pProHWX,
pProslic[k]->channel,
CALR3,
0x80); /* start cal */
i=0;
do {
data = pProslic[k]->ReadRegX(pProslic[k]->pProHWX,
pProslic[k]->channel,
CALR3);
pProslic[k]->DelayX(pProslic[k]->pProTimerX, 10);
} while (data&0x80 && ++i<=TIMEOUT_LB_CAL);
if (i >= TIMEOUT_LB_CAL) {
#ifdef ENABLE_DEBUG
if (pProslic[k]->debugMode)
LOGPRINT("Calibration timeout channel %d\n",
pProslic[k]->channel);
#endif
pProslic[k]->error = RC_CAL_TIMEOUT;
pProslic[k]->WriteRegX(pProslic[k]->pProHWX,
pProslic[k]->channel,
LINEFEED,
LF_OPEN);
timeout = 1;
} else {
pProslic[k]->WriteRegX(pProslic[k]->pProHWX,
pProslic[k]->channel,
LINEFEED,
lf[k]);
}
}
}
#ifndef DISABLE_MALLOC
free(lf);
#endif
if (timeout != 0) {
return RC_CAL_TIMEOUT;
} else {
return 0;
}
}
/*
** Function: Si3226x_GetLBCalResult
**
** Description:
** Read applicable calibration coefficients
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
** resultx: pointer to 4 RAM results
**
** Return:
** 0
*/
int Si3226x_GetLBCalResult (proslicChanType *pProslic,int32 *result1,int32 *result2,int32 *result3,int32 *result4){
setUserMode(pProslic,TRUE);
*result1 = ReadRAM(pProHW,pProslic->channel,CMDAC_FWD);
*result2 = ReadRAM(pProHW,pProslic->channel,CMDAC_REV);
*result3 = ReadRAM(pProHW,pProslic->channel,CAL_TRNRD_DACT);
*result4 = ReadRAM(pProHW,pProslic->channel,CAL_TRNRD_DACR);
setUserMode(pProslic,FALSE);
return 0;
}
/*
** Function: Si3226x_GetLBCalResultPacked
**
** Description:
** Read applicable calibration coefficients
** and pack into single 32bit word
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
** result: pointer to packed result
**
** Return:
** 0
**
** Packed Result Format
**
** Bits 31:24 CMDAC_FWD[
*/
int Si3226x_GetLBCalResultPacked (proslicChanType *pProslic,int32 *result){
int32 tmpResult;
setUserMode(pProslic,TRUE);
tmpResult = ReadRAM(pProHW,pProslic->channel,CMDAC_FWD);
*result = (tmpResult<<6)&0xff000000L;
tmpResult = ReadRAM(pProHW,pProslic->channel,CMDAC_REV);
*result |= (tmpResult>>1)&0x00ff0000L;
tmpResult = ReadRAM(pProHW,pProslic->channel,CAL_TRNRD_DACT);
*result |= (tmpResult>>5)&0x0000ff00L;
tmpResult = ReadRAM(pProHW,pProslic->channel,CAL_TRNRD_DACR);
*result |= (tmpResult>>13)&0x000000ffL;
setUserMode(pProslic,FALSE);
return 0;
}
/*
** Function: Si3226x_LoadPreviousLBCal
**
** Description:
** Load applicable calibration coefficients
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
** resultx: pointer to 4 RAM results
**
** Return:
** 0
*/
int Si3226x_LoadPreviousLBCal (proslicChanType *pProslic,int32 result1,int32 result2,int32 result3,int32 result4){
setUserMode(pProslic,TRUE);
WriteRAM(pProHW,pProslic->channel,CMDAC_FWD,result1);
WriteRAM(pProHW,pProslic->channel,CMDAC_REV,result2);
WriteRAM(pProHW,pProslic->channel,CAL_TRNRD_DACT,result3);
WriteRAM(pProHW,pProslic->channel,CAL_TRNRD_DACR,result4);
setUserMode(pProslic,FALSE);
return 0;
}
/*
** Function: Si3226x_LoadPreviousLBCalPacked
**
** Description:
** Load applicable calibration coefficients
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
** result: pointer to packed cal results
**
** Return:
** 0
*/
int Si3226x_LoadPreviousLBCalPacked (proslicChanType *pProslic,int32 *result){
int32 ramVal;
setUserMode(pProslic,TRUE);
ramVal = (*result&0xff000000L)>>6;
WriteRAM(pProHW,pProslic->channel,CMDAC_FWD,ramVal);
ramVal = (*result&0x00ff0000L)<<1;
WriteRAM(pProHW,pProslic->channel,CMDAC_REV,ramVal);
ramVal = (*result&0x0000ff00L)<<5;
WriteRAM(pProHW,pProslic->channel,CAL_TRNRD_DACT,ramVal);
ramVal = (*result&0x000000ffL)<<13;
WriteRAM(pProHW,pProslic->channel,CAL_TRNRD_DACR,ramVal);
#ifdef API_TEST
ramVal = ReadRAM(pProHW,pProslic->channel,CMDAC_FWD);
LOGPRINT ("UNPACKED CMDAC_FWD = %08x\n",ramVal);
ramVal = ReadRAM(pProHW,pProslic->channel,CMDAC_REV);
LOGPRINT ("UNPACKED CMDAC_REF = %08x\n",ramVal);
ramVal = ReadRAM(pProHW,pProslic->channel,CAL_TRNRD_DACT);
LOGPRINT ("UNPACKED CAL_TRNRD_DACT = %08x\n",ramVal);
ramVal = ReadRAM(pProHW,pProslic->channel,CAL_TRNRD_DACR);
LOGPRINT ("UNPACKED CAL_TRNRD_DACR = %08x\n",ramVal);
#endif
setUserMode(pProslic,FALSE);
return 0;
}
/*
** Function: Si3226x_LoadRegTables
**
** Description:
** Generic register and ram table loader
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel object
** pRamTable: pointer to PROSLIC ram table
** pRegTable: pointer to PROSLIC reg table
** size: number of channels
**
** Return:
** 0
*/
int Si3226x_LoadRegTables (proslicChanType_ptr *pProslic, ProslicRAMInit *pRamTable, ProslicRegInit *pRegTable, int size){
uInt16 i;
for (i=0;i<size;i++){
if (pProslic[i]->channelEnable)
LoadRegTables(pProslic[i],pRamTable,pRegTable,0);
}
return 0;
}
/*
** Function: Si3226x_LoadPatch
**
** Description:
** Calls patch loading function
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** pPatch: pointer to PROSLIC patch obj
**
** Returns:
** 0
*/
int Si3226x_LoadPatch (proslicChanType *pProslic, const proslicPatch *pPatch){
LoadSi3226xPatch(pProslic,pPatch,0);
return 0;
}
/*
** Function: Si3226x_VerifyPatch
**
** Description:
** Veriy patch load
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** pPatch: pointer to PROSLIC patch obj
**
** Returns:
** 0
*/
int Si3226x_VerifyPatch (proslicChanType *pProslic, const proslicPatch *pPatch){
int loop;
uInt8 jmp_table_low;
uInt16 jmp_table_high;
uInt8 data;
uInt32 ramdata;
int err_low = 0;
int err_high = 0;
int err_ram = 0;
if (pPatch == NULL)
return RC_NONE;
setUserMode (pProslic,TRUE); /*make sure we are in user mode to read patch*/
WriteReg (pProHW, pProslic->channel, JMPEN,0); /*disable the patch*/
WriteRAM(pProHW, pProslic->channel,PRAM_ADDR, 0); /*write patch ram address register*/
/* If the data is all 0, you have hit the end of the programmed values and can stop loading.*/
for (loop=0; loop<PATCH_MAX_SIZE; loop++){
if (pPatch->patchData[loop] != 0){
ramdata = ReadRAM(pProHW, pProslic->channel,PRAM_DATA); /*note. data is shifted*/
if (pPatch->patchData[loop]<<9 != ramdata){
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("ERROR : Addr: %d Expected: %d Actual: %d\n", loop, (int)(pPatch->patchData[loop]<<9), (int)(ramdata));
}
#endif
loop = PATCH_MAX_SIZE;
err_ram = 1;
}
}
else
loop = PATCH_MAX_SIZE;
}
if (err_ram){
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("ERROR : patch verify RAM : channel %d\n",pProslic->channel);
#endif
}
/*zero out RAM_ADDR_HI*/
WriteReg (pProHW, pProslic->channel, RAM_ADDR_HI,0);
/**
* Verify jump table low entries
*/
jmp_table_low=PATCH_JMPTBL_LOW_ADDR;
for (loop=0;loop<PATCH_NUM_LOW_ENTRIES;loop++){
/* check the jump table with the new values.*/
if (pPatch->patchEntries[loop] != 0){
data = ReadReg (pProHW, pProslic->channel, jmp_table_low);
if (data != ((pPatch->patchEntries[loop])&0xff))
err_low = 1;
data = ReadReg (pProHW, pProslic->channel, jmp_table_low+1);
if (data != (pPatch->patchEntries[loop]>>8))
err_low = 1;
}
jmp_table_low+=2;
}
if (err_low){
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("ERROR : patch verify table low : channel %d\n",pProslic->channel);
#endif
}
/**
* Verify jump table high entries
*/
jmp_table_high=PATCH_JMPTBL_HIGH_ADDR;
for (loop=0;loop<PATCH_NUM_HIGH_ENTRIES;loop++)
{
if (pPatch->patchEntries[loop+PATCH_NUM_LOW_ENTRIES] != 0)
{
ramdata = ReadRAM (pProHW, pProslic->channel, jmp_table_high);
if (ramdata != (((uInt32)(pPatch->patchEntries[loop+PATCH_NUM_LOW_ENTRIES]))&(0x00001fffL)))
err_high = 1;
}
jmp_table_high++;
}
if (err_high){
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("ERROR : patch verify table high : channel %d\n",pProslic->channel);
#endif
}
/**
* If no errors, re-enable the patch
*/
if(!(err_ram | err_low | err_high))
WriteReg (pProHW, pProslic->channel, JMPEN,1); /*enable the patch*/
setUserMode(pProslic,FALSE); /*turn off user mode*/
if(err_ram)
return RC_PATCH_RAM_VERIFY_FAIL;
else if(err_low | err_high)
return RC_PATCH_ENTRY_VERIFY_FAIL;
else
return RC_NONE;
}
/*
** Function: Si3226x_SetLoopbackMode
**
** Description:
** Program desired loopback test mode
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** newMode: desired loopback mode tag
**
** Returns:
** 0
*/
int Si3226x_SetLoopbackMode (proslicChanType_ptr pProslic, ProslicLoopbackModes newMode){
uInt8 regTemp;
regTemp = ReadReg (pProHW,pProslic->channel,LOOPBACK);
switch (newMode){
case PROSLIC_LOOPBACK_NONE:
WriteReg (pProHW,pProslic->channel,LOOPBACK,regTemp&~(0x11));
break;
case PROSLIC_LOOPBACK_DIG:
WriteReg (pProHW,pProslic->channel,LOOPBACK,regTemp|(0x1));
break;
case PROSLIC_LOOPBACK_ANA:
WriteReg (pProHW,pProslic->channel,LOOPBACK,regTemp|(0x10));
break;
}
return 0;
}
/*
** Function: Si3226x_SetMuteStatus
**
** Description:
** configure RX and TX path mutes
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** muteEn: mute configuration tag
**
** Returns:
** 0
*/
int Si3226x_SetMuteStatus (proslicChanType_ptr pProslic, ProslicMuteModes muteEn){
uInt8 regTemp;
uInt8 newRegValue;
regTemp = ReadReg (pProHW,pProslic->channel,DIGCON);
newRegValue = regTemp &~(0x3);
WriteReg (pProHW,pProslic->channel,DIGCON,regTemp&~(0x3));
if (muteEn & PROSLIC_MUTE_RX){
newRegValue |= 1;
}
if (muteEn & PROSLIC_MUTE_TX){
newRegValue |= 2;
}
if(newRegValue != regTemp)
{
WriteReg (pProHW,pProslic->channel,DIGCON,newRegValue);
}
return 0;
}
/*
** Function: Si3226x_EnableInterrupts
**
** Description:
** Enables interrupts
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
**
** Returns:
** 0
*/
int Si3226x_EnableInterrupts (proslicChanType_ptr pProslic){
WriteReg (pProHW,pProslic->channel,IRQEN1,Si3226x_General_Configuration.irqen1);
WriteReg (pProHW,pProslic->channel,IRQEN2,Si3226x_General_Configuration.irqen2);
WriteReg (pProHW,pProslic->channel,IRQEN3,Si3226x_General_Configuration.irqen3);
WriteReg (pProHW,pProslic->channel,IRQEN4,Si3226x_General_Configuration.irqen4);
return 0;
}
/*
** Function: Si3226x_DisableInterrupts
**
** Description:
** Disables/clears interrupts
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
**
** Returns:
** 0
*/
int Si3226x_DisableInterrupts (proslicChanType_ptr pProslic){
uInt8 data[4];
WriteReg (pProHW,pProslic->channel,IRQEN1,0);
WriteReg (pProHW,pProslic->channel,IRQEN2,0);
WriteReg (pProHW,pProslic->channel,IRQEN3,0);
WriteReg (pProHW,pProslic->channel,IRQEN4,0);
data[0] = ReadReg(pProHW,pProslic->channel,IRQ1);
data[1] = ReadReg(pProHW,pProslic->channel,IRQ2);
data[2] = ReadReg(pProHW,pProslic->channel,IRQ3);
data[3] = ReadReg(pProHW,pProslic->channel,IRQ4);
#ifdef GCI_MODE
WriteReg(pProHW,pProslic->channel,IRQ1,data[0]); /*clear interrupts (gci only)*/
WriteReg(pProHW,pProslic->channel,IRQ2,data[1]);
WriteReg(pProHW,pProslic->channel,IRQ3,data[2]);
WriteReg(pProHW,pProslic->channel,IRQ4,data[3]);
#endif
return RC_NONE;
}
/*
** Function: Si3226x_CheckCIDBuffer
**
** Description:
** configure fsk
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** fskBufAvail: fsk buffer available flag
**
** Returns:
** 0
*/
int Si3226x_CheckCIDBuffer (proslicChanType *pProslic, uInt8 *fskBufAvail){
uInt8 data;
data = ReadReg(pProHW,pProslic->channel,IRQ1);
WriteReg(pProHW,pProslic->channel,IRQ1,data); /*clear (for GCI)*/
*fskBufAvail = (data&0x40) ? 1 : 0;
return 0;
}
/*
**
** PROSLIC CONFIGURATION FUNCTIONS
**
*/
/*
** Function: Si3226x_RingSetup
**
** Description:
** configure ringing
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** preset: ring preset
**
** Returns:
** 0
*/
#ifndef DISABLE_RING_SETUP
int Si3226x_RingSetup (proslicChanType *pProslic, int preset){
WriteRAM(pProHW,pProslic->channel,RTPER,Si3226x_Ring_Presets[preset].rtper);
WriteRAM(pProHW,pProslic->channel,RINGFR,Si3226x_Ring_Presets[preset].freq);
WriteRAM(pProHW,pProslic->channel,RINGAMP,Si3226x_Ring_Presets[preset].amp);
WriteRAM(pProHW,pProslic->channel,RINGPHAS,Si3226x_Ring_Presets[preset].phas);
WriteRAM(pProHW,pProslic->channel,RINGOF,Si3226x_Ring_Presets[preset].offset);
WriteRAM(pProHW,pProslic->channel,SLOPE_RING,Si3226x_Ring_Presets[preset].slope_ring);
WriteRAM(pProHW,pProslic->channel,IRING_LIM,Si3226x_Ring_Presets[preset].iring_lim);
WriteRAM(pProHW,pProslic->channel,RTACTH,Si3226x_Ring_Presets[preset].rtacth);
WriteRAM(pProHW,pProslic->channel,RTDCTH,Si3226x_Ring_Presets[preset].rtdcth);
WriteRAM(pProHW,pProslic->channel,RTACDB,Si3226x_Ring_Presets[preset].rtacdb);
WriteRAM(pProHW,pProslic->channel,RTDCDB,Si3226x_Ring_Presets[preset].rtdcdb);
WriteRAM(pProHW,pProslic->channel,VOV_RING_BAT,Si3226x_Ring_Presets[preset].vov_ring_bat);
WriteRAM(pProHW,pProslic->channel,VOV_RING_GND,Si3226x_Ring_Presets[preset].vov_ring_gnd);
/* Always limit VBATR_EXPECT to the general configuration maximum */
#ifndef NOCLAMP_VBATR
if(Si3226x_Ring_Presets[preset].vbatr_expect > Si3226x_General_Configuration.vbatr_expect)
{
WriteRAM(pProHW,pProslic->channel,VBATR_EXPECT,Si3226x_General_Configuration.vbatr_expect);
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("ProSLIC_RingSetup : VBATR_EXPECT : Clamped to Gen Conf Limit\n");
}
#endif
}
else
{
WriteRAM(pProHW,pProslic->channel,VBATR_EXPECT,Si3226x_Ring_Presets[preset].vbatr_expect);
}
#else
WriteRAM(pProHW,pProslic->channel,VBATR_EXPECT,Si3226x_Ring_Presets[preset].vbatr_expect);
#endif
WriteReg(pProHW,pProslic->channel,RINGTALO,Si3226x_Ring_Presets[preset].talo);
WriteReg(pProHW,pProslic->channel,RINGTAHI,Si3226x_Ring_Presets[preset].tahi);
WriteReg(pProHW,pProslic->channel,RINGTILO,Si3226x_Ring_Presets[preset].tilo);
WriteReg(pProHW,pProslic->channel,RINGTIHI,Si3226x_Ring_Presets[preset].tihi);
WriteRAM(pProHW,pProslic->channel,DCDC_VREF_MIN_RNG,Si3226x_Ring_Presets[preset].vbat_track_min_rng);
WriteReg(pProHW,pProslic->channel,RINGCON,Si3226x_Ring_Presets[preset].ringcon);
WriteReg(pProHW,pProslic->channel,USERSTAT,Si3226x_Ring_Presets[preset].userstat);
WriteRAM(pProHW,pProslic->channel,VCM_RING,Si3226x_Ring_Presets[preset].vcm_ring);
WriteRAM(pProHW,pProslic->channel,VCM_RING_FIXED,Si3226x_Ring_Presets[preset].vcm_ring_fixed);
WriteRAM(pProHW,pProslic->channel,DELTA_VCM,Si3226x_Ring_Presets[preset].delta_vcm);
WriteRAM(pProHW,pProslic->channel,VOV_DCDC_SLOPE,Si3226x_Ring_Presets[preset].vov_dcdc_slope);
WriteRAM(pProHW,pProslic->channel,VOV_DCDC_OS,Si3226x_Ring_Presets[preset].vov_dcdc_os);
WriteRAM(pProHW,pProslic->channel,VOV_RING_BAT_MAX,Si3226x_Ring_Presets[preset].vov_ring_bat_max);
setUserMode(pProslic,TRUE);
WriteRAM(pProHW,pProslic->channel,DCDC_RNGTYPE,Si3226x_Ring_Presets[preset].dcdc_rngtype);
setUserMode(pProslic,FALSE);
return 0;
}
#endif
/*
** Function: Si3226x_ToneGenSetup
**
** Description:
** configure tone generators
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** preset: tone generator preset
**
** Returns:
** 0
*/
#ifndef DISABLE_TONE_SETUP
int Si3226x_ToneGenSetup (proslicChanType *pProslic, int preset){
WriteRAM(pProHW,pProslic->channel,OSC1FREQ,Si3226x_Tone_Presets[preset].osc1.freq);
WriteRAM(pProHW,pProslic->channel,OSC1AMP,Si3226x_Tone_Presets[preset].osc1.amp);
WriteRAM(pProHW,pProslic->channel,OSC1PHAS,Si3226x_Tone_Presets[preset].osc1.phas);
WriteReg(pProHW,pProslic->channel,O1TAHI,(Si3226x_Tone_Presets[preset].osc1.tahi));
WriteReg(pProHW,pProslic->channel,O1TALO,(Si3226x_Tone_Presets[preset].osc1.talo));
WriteReg(pProHW,pProslic->channel,O1TIHI,(Si3226x_Tone_Presets[preset].osc1.tihi));
WriteReg(pProHW,pProslic->channel,O1TILO,(Si3226x_Tone_Presets[preset].osc1.tilo));
WriteRAM(pProHW,pProslic->channel,OSC2FREQ,Si3226x_Tone_Presets[preset].osc2.freq);
WriteRAM(pProHW,pProslic->channel,OSC2AMP,Si3226x_Tone_Presets[preset].osc2.amp);
WriteRAM(pProHW,pProslic->channel,OSC2PHAS,Si3226x_Tone_Presets[preset].osc2.phas);
WriteReg(pProHW,pProslic->channel,O2TAHI,(Si3226x_Tone_Presets[preset].osc2.tahi));
WriteReg(pProHW,pProslic->channel,O2TALO,(Si3226x_Tone_Presets[preset].osc2.talo));
WriteReg(pProHW,pProslic->channel,O2TIHI,(Si3226x_Tone_Presets[preset].osc2.tihi));
WriteReg(pProHW,pProslic->channel,O2TILO,(Si3226x_Tone_Presets[preset].osc2.tilo));
WriteReg(pProHW,pProslic->channel,OMODE,(Si3226x_Tone_Presets[preset].omode));
return 0;
}
#endif
/*
** Function: Si3226x_FSKSetup
**
** Description:
** configure fsk
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** preset: fsk preset
**
** Returns:
** 0
*/
#ifndef DISABLE_FSK_SETUP
int Si3226x_FSKSetup (proslicChanType *pProslic, int preset){
uInt8 data;
WriteReg(pProHW,pProslic->channel,O1TAHI,0);
WriteReg(pProHW,pProslic->channel,O1TIHI,0);
WriteReg(pProHW,pProslic->channel,O1TILO,0);
WriteReg(pProHW,pProslic->channel,O1TALO,0x13);
data = ReadReg(pProHW,pProslic->channel,OMODE);
if (Si3226x_FSK_Presets[preset].eightBit)
data |= 0x80;
else
data &= ~(0x80);
WriteReg(pProHW,pProslic->channel,FSKDEPTH,Si3226x_FSK_Presets[preset].fskdepth);
WriteReg(pProHW,pProslic->channel,OMODE,data);
WriteRAM(pProHW,pProslic->channel,FSK01,Si3226x_FSK_Presets[preset].fsk01);
WriteRAM(pProHW,pProslic->channel,FSK10,Si3226x_FSK_Presets[preset].fsk10);
WriteRAM(pProHW,pProslic->channel,FSKAMP0,Si3226x_FSK_Presets[preset].fskamp0);
WriteRAM(pProHW,pProslic->channel,FSKAMP1,Si3226x_FSK_Presets[preset].fskamp1);
WriteRAM(pProHW,pProslic->channel,FSKFREQ0,Si3226x_FSK_Presets[preset].fskfreq0);
WriteRAM(pProHW,pProslic->channel,FSKFREQ1,Si3226x_FSK_Presets[preset].fskfreq1);
return 0;
}
#endif
/*
* Function: Si3226x_ModifyStartBits
*
* Description: To change the FSK start/stop bits field.
* Returns RC_NONE if OK.
*/
int Si3226x_ModifyCIDStartBits(proslicChanType_ptr pProslic, uInt8 enable_startStop)
{
uInt8 data;
if(pProslic->channelType != PROSLIC)
{
return RC_CHANNEL_TYPE_ERR;
}
data = ReadReg(pProHW,pProslic->channel,OMODE);
if(enable_startStop == FALSE)
{
data &= ~0x80;
}
else
{
data |= 0x80;
}
WriteReg(pProHW,pProslic->channel,OMODE,data);
return RC_NONE;
}
/*
** Function: Si3226x_DTMFDecodeSetup
**
** Description:
** configure dtmf decode
**
** Input Parameters:
** pProslic: pointer to PROSLIC channel obj
** preset: dtmf preset
**
** Returns:
** 0
*/
#ifndef DISABLE_DTMF_SETUP
int Si3226x_DTMFDecodeSetup (proslicChanType *pProslic, int preset){
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B0_1,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b0_1);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B1_1,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b1_1);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B2_1,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b2_1);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_A1_1,Si3226x_DTMFDec_Presets[preset].dtmfdtf_a1_1);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_A2_1,Si3226x_DTMFDec_Presets[preset].dtmfdtf_a2_1);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B0_2,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b0_2);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B1_2,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b1_2);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B2_2,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b2_2);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_A1_2,Si3226x_DTMFDec_Presets[preset].dtmfdtf_a1_2);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_A2_2,Si3226x_DTMFDec_Presets[preset].dtmfdtf_a2_2);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B0_3,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b0_3);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B1_3,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b1_3);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_B2_3,Si3226x_DTMFDec_Presets[preset].dtmfdtf_b2_3);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_A1_3,Si3226x_DTMFDec_Presets[preset].dtmfdtf_a1_3);
WriteRAM(pProHW,pProslic->channel,DTMFDTF_A2_3,Si3226x_DTMFDec_Presets[preset].dtmfdtf_a2_3);
return 0;
}
#endif
/*
** Function: PROSLIC_SetProfile
**
** Description:
** set country profile of the proslic
*/
int Si3226x_SetProfile (proslicChanType *pProslic, int preset){
/*TO DO
Will be filled in at a later date*/
return 0;
}
/*
** Function: PROSLIC_ZsynthSetup
**
** Description:
** configure impedence synthesis
*/
#ifndef DISABLE_ZSYNTH_SETUP
int Si3226x_ZsynthSetup (proslicChanType *pProslic, int preset){
uInt8 lf;
uInt8 cal_en = 0;
uInt16 timer = 500;
lf = ReadReg(pProHW,pProslic->channel,LINEFEED);
WriteReg(pProHW,pProslic->channel,LINEFEED,0);
/*
** Load provided coefficients - these are presumed to be 0dB/0dB
*/
WriteRAM(pProHW,pProslic->channel,TXACEQ_C0,Si3226x_Impedance_Presets[preset].audioEQ.txaceq_c0);
WriteRAM(pProHW,pProslic->channel,TXACEQ_C1,Si3226x_Impedance_Presets[preset].audioEQ.txaceq_c1);
WriteRAM(pProHW,pProslic->channel,TXACEQ_C2,Si3226x_Impedance_Presets[preset].audioEQ.txaceq_c2);
WriteRAM(pProHW,pProslic->channel,TXACEQ_C3,Si3226x_Impedance_Presets[preset].audioEQ.txaceq_c3);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C0,Si3226x_Impedance_Presets[preset].audioEQ.rxaceq_c0);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C1,Si3226x_Impedance_Presets[preset].audioEQ.rxaceq_c1);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C2,Si3226x_Impedance_Presets[preset].audioEQ.rxaceq_c2);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C3,Si3226x_Impedance_Presets[preset].audioEQ.rxaceq_c3);
WriteRAM(pProHW,pProslic->channel,ECFIR_C2,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c2);
WriteRAM(pProHW,pProslic->channel,ECFIR_C3,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c3);
WriteRAM(pProHW,pProslic->channel,ECFIR_C4,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c4);
WriteRAM(pProHW,pProslic->channel,ECFIR_C5,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c5);
WriteRAM(pProHW,pProslic->channel,ECFIR_C6,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c6);
WriteRAM(pProHW,pProslic->channel,ECFIR_C7,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c7);
WriteRAM(pProHW,pProslic->channel,ECFIR_C8,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c8);
WriteRAM(pProHW,pProslic->channel,ECFIR_C9,Si3226x_Impedance_Presets[preset].hybrid.ecfir_c9);
WriteRAM(pProHW,pProslic->channel,ECIIR_B0,Si3226x_Impedance_Presets[preset].hybrid.ecfir_b0);
WriteRAM(pProHW,pProslic->channel,ECIIR_B1,Si3226x_Impedance_Presets[preset].hybrid.ecfir_b1);
WriteRAM(pProHW,pProslic->channel,ECIIR_A1,Si3226x_Impedance_Presets[preset].hybrid.ecfir_a1);
WriteRAM(pProHW,pProslic->channel,ECIIR_A2,Si3226x_Impedance_Presets[preset].hybrid.ecfir_a2);
WriteRAM(pProHW,pProslic->channel,ZSYNTH_A1,Si3226x_Impedance_Presets[preset].zsynth.zsynth_a1);
WriteRAM(pProHW,pProslic->channel,ZSYNTH_A2,Si3226x_Impedance_Presets[preset].zsynth.zsynth_a2);
WriteRAM(pProHW,pProslic->channel,ZSYNTH_B1,Si3226x_Impedance_Presets[preset].zsynth.zsynth_b1);
WriteRAM(pProHW,pProslic->channel,ZSYNTH_B0,Si3226x_Impedance_Presets[preset].zsynth.zsynth_b0);
WriteRAM(pProHW,pProslic->channel,ZSYNTH_B2,Si3226x_Impedance_Presets[preset].zsynth.zsynth_b2);
WriteReg(pProHW,pProslic->channel,RA,Si3226x_Impedance_Presets[preset].zsynth.ra);
WriteRAM(pProHW,pProslic->channel,TXACGAIN,Si3226x_Impedance_Presets[preset].txgain);
WriteRAM(pProHW,pProslic->channel,RXACGAIN_SAVE,Si3226x_Impedance_Presets[preset].rxgain);
WriteRAM(pProHW,pProslic->channel,RXACGAIN,Si3226x_Impedance_Presets[preset].rxgain);
WriteRAM(pProHW,pProslic->channel,RXACHPF_B0_1,Si3226x_Impedance_Presets[preset].rxachpf_b0_1);
WriteRAM(pProHW,pProslic->channel,RXACHPF_B1_1,Si3226x_Impedance_Presets[preset].rxachpf_b1_1);
WriteRAM(pProHW,pProslic->channel,RXACHPF_A1_1,Si3226x_Impedance_Presets[preset].rxachpf_a1_1);
/*
** Scale based on desired gain plan
*/
Si3226x_dbgSetTXGain(pProslic,Si3226x_Impedance_Presets[preset].txgain_db,preset,TXACGAIN_SEL);
Si3226x_dbgSetRXGain(pProslic,Si3226x_Impedance_Presets[preset].rxgain_db,preset,RXACGAIN_SEL);
Si3226x_TXAudioGainSetup(pProslic,TXACGAIN_SEL);
Si3226x_RXAudioGainSetup(pProslic,RXACGAIN_SEL);
/*
** Perform Zcal in case OHT used (eg. no offhook event to trigger auto Zcal)
*/
WriteReg(pProHW,pProslic->channel,CALR0,0x00);
WriteReg(pProHW,pProslic->channel,CALR1,0x40);
WriteReg(pProHW,pProslic->channel,CALR2,0x00);
WriteReg(pProHW,pProslic->channel,CALR3,0x80); /* start cal */
/* Wait for zcal to finish */
do {
cal_en = ReadReg(pProHW,pProslic->channel,CALR3);
Delay(pProTimer,1);
timer--;
}while((cal_en&0x80)&&(timer>0));
WriteReg(pProHW,pProslic->channel,LINEFEED,lf);
if(timer > 0) return 0;
else return RC_CAL_TIMEOUT;
}
#endif
/*
** Function: PROSLIC_GciCISetup
**
** Description:
** configure CI bits (GCI mode)
*/
#ifndef DISABLE_CI_SETUP
int Si3226x_GciCISetup (proslicChanType *pProslic, int preset){
WriteReg(pProHW,pProslic->channel,GCI_CI,Si3226x_CI_Presets[preset].gci_ci);
return 0;
}
#endif
/*
** Function: PROSLIC_ModemDetSetup
**
** Description:
** configure modem detector
*/
int Si3226x_ModemDetSetup (proslicChanType *pProslic, int preset){
/*TO DO
Will be filled in at a later date*/
return 0;
}
/*
** Function: PROSLIC_AudioGainSetup
**
** Description:
** configure audio gains
*/
int Si3226x_TXAudioGainSetup (proslicChanType *pProslic, int preset){
WriteRAM(pProHW,pProslic->channel,TXACGAIN,Si3226x_audioGain_Presets[preset].acgain);
WriteRAM(pProHW,pProslic->channel,TXACEQ_C0,Si3226x_audioGain_Presets[preset].aceq_c0);
WriteRAM(pProHW,pProslic->channel,TXACEQ_C1,Si3226x_audioGain_Presets[preset].aceq_c1);
WriteRAM(pProHW,pProslic->channel,TXACEQ_C2,Si3226x_audioGain_Presets[preset].aceq_c2);
WriteRAM(pProHW,pProslic->channel,TXACEQ_C3,Si3226x_audioGain_Presets[preset].aceq_c3);
return 0;
}
/*
** Function: PROSLIC_AudioGainSetup
**
** Description:
** configure audio gains
*/
int Si3226x_RXAudioGainSetup (proslicChanType *pProslic, int preset){
WriteRAM(pProHW,pProslic->channel,RXACGAIN_SAVE,Si3226x_audioGain_Presets[preset].acgain);
WriteRAM(pProHW,pProslic->channel,RXACGAIN,Si3226x_audioGain_Presets[preset].acgain);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C0,Si3226x_audioGain_Presets[preset].aceq_c0);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C1,Si3226x_audioGain_Presets[preset].aceq_c1);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C2,Si3226x_audioGain_Presets[preset].aceq_c2);
WriteRAM(pProHW,pProslic->channel,RXACEQ_C3,Si3226x_audioGain_Presets[preset].aceq_c3);
return 0;
}
/*
** Function: PROSLIC_DCFeedSetupCfg
**
** Description:
** configure dc feed
*/
#ifndef DISABLE_DCFEED_SETUP
int Si3226x_DCFeedSetupCfg (proslicChanType *pProslic, Si3226x_DCfeed_Cfg *cfg, int preset){
uInt8 lf;
if(pProslic->channelType != PROSLIC) {
return RC_CHANNEL_TYPE_ERR;
}
lf = ReadReg(pProHW,pProslic->channel,LINEFEED);
WriteReg(pProHW,pProslic->channel,LINEFEED,0);
WriteRAM(pProHW,pProslic->channel,SLOPE_VLIM,cfg[preset].slope_vlim);
WriteRAM(pProHW,pProslic->channel,SLOPE_RFEED,cfg[preset].slope_rfeed);
WriteRAM(pProHW,pProslic->channel,SLOPE_ILIM,cfg[preset].slope_ilim);
WriteRAM(pProHW,pProslic->channel,SLOPE_DELTA1,cfg[preset].delta1);
WriteRAM(pProHW,pProslic->channel,SLOPE_DELTA2,cfg[preset].delta2);
WriteRAM(pProHW,pProslic->channel,V_VLIM,cfg[preset].v_vlim);
WriteRAM(pProHW,pProslic->channel,V_RFEED,cfg[preset].v_rfeed);
WriteRAM(pProHW,pProslic->channel,V_ILIM,cfg[preset].v_ilim);
WriteRAM(pProHW,pProslic->channel,CONST_RFEED,cfg[preset].const_rfeed);
WriteRAM(pProHW,pProslic->channel,CONST_ILIM,cfg[preset].const_ilim);
WriteRAM(pProHW,pProslic->channel,I_VLIM,cfg[preset].i_vlim);
WriteRAM(pProHW,pProslic->channel,LCRONHK,cfg[preset].lcronhk);
WriteRAM(pProHW,pProslic->channel,LCROFFHK,cfg[preset].lcroffhk);
WriteRAM(pProHW,pProslic->channel,LCRDBI,cfg[preset].lcrdbi);
WriteRAM(pProHW,pProslic->channel,LONGHITH,cfg[preset].longhith);
WriteRAM(pProHW,pProslic->channel,LONGLOTH,cfg[preset].longloth);
WriteRAM(pProHW,pProslic->channel,LONGDBI,cfg[preset].longdbi);
WriteRAM(pProHW,pProslic->channel,LCRMASK,cfg[preset].lcrmask);
WriteRAM(pProHW,pProslic->channel,LCRMASK_POLREV,cfg[preset].lcrmask_polrev);
WriteRAM(pProHW,pProslic->channel,LCRMASK_STATE,cfg[preset].lcrmask_state);
WriteRAM(pProHW,pProslic->channel,LCRMASK_LINECAP,cfg[preset].lcrmask_linecap);
WriteRAM(pProHW,pProslic->channel,VCM_OH,cfg[preset].vcm_oh);
WriteRAM(pProHW,pProslic->channel,VOV_BAT,cfg[preset].vov_bat);
WriteRAM(pProHW,pProslic->channel,VOV_GND,cfg[preset].vov_gnd);
#ifdef SIVOICE_MULTI_BOM_SUPPORT
#define VOV_BAT_6V 0x624DD2L /* 6v */
if(Si3226x_General_Configuration.bomOpt == BO_DCDC_FIXED_RAIL)
{
WriteRAM(pProHW,pProslic->channel,VOV_BAT,VOV_BAT_6V);
}
#endif
WriteReg(pProHW,pProslic->channel,LINEFEED,lf);
return RC_NONE;
}
/*
** Function: PROSLIC_DCFeedSetup
**
** Description:
** configure dc feed
*/
int Si3226x_DCFeedSetup (proslicChanType *pProslic, int preset){
Si3226x_DCFeedSetupCfg(pProslic,Si3226x_DCfeed_Presets,preset);
return RC_NONE;
}
#endif
/*
** Function: PROSLIC_GPIOSetup
**
** Description:
** configure gpio
*/
#ifndef DISABLE_GPIO_SETUP
int Si3226x_GPIOSetup (proslicChanType *pProslic){
uInt8 data;
data = ReadReg(pProHW,pProslic->channel,GPIO);
data |= Si3226x_GPIO_Configuration.outputEn << 4;
WriteReg(pProHW,pProslic->channel,GPIO,data);
data = Si3226x_GPIO_Configuration.analog << 4;
data |= Si3226x_GPIO_Configuration.direction;
WriteReg(pProHW,pProslic->channel,GPIO_CFG1,data);
data = Si3226x_GPIO_Configuration.manual << 4;
data |= Si3226x_GPIO_Configuration.polarity;
WriteReg(pProHW,pProslic->channel,GPIO_CFG2,data);
data |= Si3226x_GPIO_Configuration.openDrain;
WriteReg(pProHW,pProslic->channel,GPIO_CFG3,data);
return 0;
}
#endif
/*
** Function: PROSLIC_PulseMeterSetup
**
** Description:
** configure pulse metering
*/
#ifndef DISABLE_PULSE_SETUP
int Si3226x_PulseMeterSetup (proslicChanType *pProslic, int preset){
uInt8 reg;
WriteRAM(pProHW,pProslic->channel,PM_AMP_THRESH,Si3226x_PulseMeter_Presets[preset].pm_amp_thresh);
reg = (Si3226x_PulseMeter_Presets[preset].pmFreq<<1) | (Si3226x_PulseMeter_Presets[preset].pmRampRate<<4);
WriteReg(pProHW,pProslic->channel,PMCON,reg);
return 0;
}
#endif
/*
** Function: PROSLIC_PCMSetup
**
** Description:
** configure pcm
*/
#ifndef DISABLE_PCM_SETUP
int Si3226x_PCMSetup (proslicChanType *pProslic, int preset){
uInt8 regTemp;
if (Si3226x_PCM_Presets[preset].widebandEn){
regTemp = ReadReg(pProHW,pProslic->channel,DIGCON);
WriteReg(pProHW,pProslic->channel,DIGCON,regTemp|0xC);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B0_1,0x27EA83L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B1_1,0x27EA83L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A1_1,0x487977EL);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B0_2,0x8000000L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B1_2,0x7E8704DL);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B2_2,0x8000000L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A1_2,0x368C302L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A2_2,0x18EBB1A4L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B0_3,0x8000000L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B1_3,0x254C75AL);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B2_3,0x7FFFFFFL);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A1_3,0x639A165L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A2_3,0x1B6738A0L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B0_1,0x4FD507L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B1_1,0x4FD507L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A1_1,0x487977EL);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B0_2,0x8000000L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B1_2,0x7E8704DL);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B2_2,0x8000000L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A1_2,0x368C302L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A2_2,0x18EBB1A4L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B0_3,0x8000000L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B1_3,0x254C75AL);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B2_3,0x7FFFFFFL);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A1_3,0x639A165L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A2_3,0x1B6738A0L);
regTemp = ReadReg(pProHW,pProslic->channel,ENHANCE);
WriteReg(pProHW,pProslic->channel,ENHANCE,regTemp|1);
} else {
regTemp = ReadReg(pProHW,pProslic->channel,DIGCON);
WriteReg(pProHW,pProslic->channel,DIGCON,regTemp&~(0xC));
WriteRAM(pProHW,pProslic->channel,TXACIIR_B0_1,0x3538E80L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B1_1,0x3538E80L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A1_1,0x1AA9100L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B0_2,0x216D100L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B1_2,0x2505400L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B2_2,0x216D100L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A1_2,0x2CB8100L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A2_2,0x1D7FA500L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B0_3,0x2CD9B00L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B1_3,0x1276D00L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_B2_3,0x2CD9B00L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A1_3,0x2335300L);
WriteRAM(pProHW,pProslic->channel,TXACIIR_A2_3,0x19D5F700L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B0_1,0x6A71D00L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B1_1,0x6A71D00L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A1_1,0x1AA9100L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B0_2,0x216D100L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B1_2,0x2505400L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B2_2,0x216D100L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A1_2,0x2CB8100L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A2_2,0x1D7FA500L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B0_3,0x2CD9B00L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B1_3,0x1276D00L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_B2_3,0x2CD9B00L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A1_3,0x2335300L);
WriteRAM(pProHW,pProslic->channel,RXACIIR_A2_3,0x19D5F700L);
regTemp = ReadReg(pProHW,pProslic->channel,ENHANCE);
WriteReg(pProHW,pProslic->channel,ENHANCE,regTemp&~(1));
}
regTemp = Si3226x_PCM_Presets[preset].pcmFormat;
regTemp |= Si3226x_PCM_Presets[preset].pcm_tri << 5;
regTemp |= Si3226x_PCM_Presets[preset].alaw_inv << 2;
WriteReg(pProHW,pProslic->channel,PCMMODE,regTemp);
regTemp = ReadReg(pProHW,pProslic->channel,PCMTXHI);
regTemp &= 3;
regTemp |= Si3226x_PCM_Presets[preset].tx_edge<<4;
WriteReg(pProHW,pProslic->channel,PCMTXHI,regTemp);
return 0;
}
#endif
/*
** Function: PROSLIC_PCMSetup
**
** Description:
** configure pcm
*/
int Si3226x_PCMTimeSlotSetup (proslicChanType *pProslic, uInt16 rxcount, uInt16 txcount){
uInt8 data;
data = txcount & 0xff;
WriteReg(pProHW,pProslic->channel,PCMTXLO,data);
data = txcount >> 8 ;
WriteReg(pProHW,pProslic->channel,PCMTXHI,data);
data = rxcount & 0xff;
WriteReg(pProHW,pProslic->channel,PCMRXLO,data);
data = rxcount >> 8 ;
WriteReg(pProHW,pProslic->channel,PCMRXHI,data);
return 0;
}
/*
**
** PROSLIC CONTROL FUNCTIONS
**
*/
/*
** Function: PROSLIC_GetInterrupts
**
** Description:
** Reads interrupt registers status (IRQ1-4)
**
** Returns:
** array of pending interrupts of type proslicIntType*
**
*/
int Si3226x_GetInterrupts (proslicChanType *pProslic,proslicIntType *pIntData){
/*Reading the interrupt registers and will clear any bits which are set (SPI mode only)
Multiple interrupts may occur at once so bear that in mind when
writing an interrupt handling routine*/
uInt8 data[4];
int i,j,k;
int safetyInt = 0;
pIntData->number = 0;
if(pProslic->channelType != PROSLIC) {
return RC_IGNORE;
}
data[0] = ReadReg(pProHW,pProslic->channel,IRQ1);
data[1] = ReadReg(pProHW,pProslic->channel,IRQ2);
data[2] = ReadReg(pProHW,pProslic->channel,IRQ3);
data[3] = ReadReg(pProHW,pProslic->channel,IRQ4);
#ifdef GCI_MODE
WriteReg(pProHW,pProslic->channel,IRQ1,data[0]); /*clear interrupts (gci only)*/
WriteReg(pProHW,pProslic->channel,IRQ2,data[1]);
WriteReg(pProHW,pProslic->channel,IRQ3,data[2]);
WriteReg(pProHW,pProslic->channel,IRQ4,data[3]);
#endif
for (i=0;i<4;i++){
for (j=0;j<8;j++){
if (data[i]&(1<<j)){
switch (j + (i*8)){
/* IRQ 1 */
case IRQ_OSC1_T1_SI3226X: /* IRQ1.0 */
k=IRQ_OSC1_T1;
break;
case IRQ_OSC1_T2_SI3226X: /* IRQ1.1 */
k=IRQ_OSC1_T2;
break;
case IRQ_OSC2_T1_SI3226X: /* IRQ1.2 */
k=IRQ_OSC2_T1;
break;
case IRQ_OSC2_T2_SI3226X: /* IRQ1.3 */
k=IRQ_OSC2_T2;
break;
case IRQ_RING_T1_SI3226X: /* IRQ1.4 */
k=IRQ_RING_T1;
break;
case IRQ_RING_T2_SI3226X: /* IRQ1.5 */
k=IRQ_RING_T2;
break;
case IRQ_FSKBUF_AVAIL_SI3226X:/* IRQ1.6 */
k=IRQ_FSKBUF_AVAIL;
break;
case IRQ_VBAT_SI3226X: /* IRQ1.7 */
k=IRQ_VBAT;
break;
/* IRQ2 */
case IRQ_RING_TRIP_SI3226X: /* IRQ2.0 */
k=IRQ_RING_TRIP;
break;
case IRQ_LOOP_STAT_SI3226X: /* IRQ2.1 */
k=IRQ_LOOP_STATUS;
break;
case IRQ_LONG_STAT_SI3226X: /* IRQ2.2 */
k=IRQ_LONG_STAT;
break;
case IRQ_VOC_TRACK_SI3226X: /* IRQ2.3 */
k=IRQ_VOC_TRACK;
break;
case IRQ_DTMF_SI3226X: /* IRQ2.4 */
k=IRQ_DTMF;
break;
case IRQ_INDIRECT_SI3226X: /* IRQ2.5 */
k=IRQ_INDIRECT;
break;
case IRQ_TXMDM_SI3226X: /* IRQ2.6 */
k = IRQ_TXMDM;
break;
case IRQ_RXMDM_SI3226X: /* IRQ2.7 */
k=IRQ_RXMDM;
break;
/* IRQ3 */
case IRQ_P_HVIC_SI3226X: /* IRQ3.0 */
k=IRQ_P_HVIC;
safetyInt = 1;
break;
case IRQ_P_THERM_SI3226X: /* IRQ3.1 */
k=IRQ_P_THERM;
safetyInt = 1;
break;
case IRQ_PQ3_SI3226X: /* IRQ3.2 */
k=IRQ_PQ3;
break;
case IRQ_PQ4_SI3226X: /* IRQ3.3 */
k=IRQ_PQ4;
break;
case IRQ_PQ5_SI3226X: /* IRQ3.4 */
k=IRQ_PQ5;
break;
case IRQ_PQ6_SI3226X: /* IRQ3.5 */
k=IRQ_PQ6;
break;
case IRQ_DSP_SI3226X: /* IRQ3.6 */
k=IRQ_DSP;
break;
case IRQ_MADC_FS_SI3226X: /* IRQ3.7 */
k=IRQ_MADC_FS;
break;
/* IRQ4 */
case IRQ_USER_0_SI3226X: /* IRQ4.0 */
k=IRQ_USER_0;
break;
case IRQ_USER_1_SI3226X: /* IRQ4.1 */
k=IRQ_USER_1;
break;
case IRQ_USER_2_SI3226X: /* IRQ4.2 */
k=IRQ_USER_2;
break;
case IRQ_USER_3_SI3226X: /* IRQ4.3 */
k=IRQ_USER_3;
break;
case IRQ_USER_4_SI3226X: /* IRQ4.4 */
k=IRQ_USER_4;
break;
case IRQ_USER_5_SI3226X: /* IRQ4.5 */
k=IRQ_USER_5;
break;
case IRQ_USER_6_SI3226X: /* IRQ4.6 */
k=IRQ_USER_6;
break;
case IRQ_USER_7_SI3226X: /* IRQ4.7 */
k=IRQ_USER_7;
break;
default:
k=0xff;
}/* switch */
pIntData->irqs[pIntData->number] = k;
pIntData->number++;
}/* if */
}/* for */
}
/* Check for improper Ring Exit if safety interrupt */
if(safetyInt)
{
if(isReinitRequired(pProslic))
{
return RC_REINIT_REQUIRED;
}
}
return pIntData->number;
}
/*
** Function: PROSLIC_ReadHookStatus
**
** Description:
** Determine hook status
*/
int Si3226x_ReadHookStatus (proslicChanType *pProslic,uInt8 *pHookStat){
if (ReadReg(pProHW,pProslic->channel,LCRRTP) & 2)
*pHookStat=PROSLIC_OFFHOOK;
else
*pHookStat=PROSLIC_ONHOOK;
return 0;
}
/*
** Function: PROSLIC_SetLinefeedStatus
**
** Description:
** Sets linefeed state
*/
int Si3226x_SetLinefeedStatus (proslicChanType *pProslic,uInt8 newLinefeed){
uInt8 regTemp;
WriteReg (pProHW, pProslic->channel, LINEFEED,newLinefeed);
if ((newLinefeed&0xf) == LF_RINGING) {
/*disable vbat interrupt during ringing*/
regTemp = ReadReg(pProHW,pProslic->channel,IRQEN1);
WriteReg (pProHW,pProslic->channel,IRQEN1,regTemp&(~0x80));
}
else{
if (pProslic->deviceId->chipRev != 0) {
regTemp = ReadReg(pProHW,pProslic->channel,IRQEN1);
if (regTemp != 0)
WriteReg (pProHW,pProslic->channel,IRQEN1,0x80 | regTemp);
}
}
return 0;
}
/*
** Function: Si324x_SetLinefeedStatusBroadcast
**
** Description:
** Sets linefeed state
*/
int Si3226x_SetLinefeedStatusBroadcast (proslicChanType *pProslic, uInt8 newLinefeed){
WriteReg (pProHW, BROADCAST, LINEFEED,newLinefeed);
return 0;
}
/*
** Function: PROSLIC_PolRev
**
** Description:
** Sets polarity reversal state
*/
int Si3226x_PolRev (proslicChanType *pProslic,uInt8 abrupt, uInt8 newPolRevState){
uInt8 data=0;
switch (newPolRevState){
case POLREV_STOP:
data = 0;
break;
case POLREV_START:
data = 2;
break;
case WINK_START:
data = 6;
break;
case WINK_STOP:
data = 4;
break;
}
if (abrupt)
data |= 1;
WriteReg(pProHW,pProslic->channel,POLREV,data);
return 0;
}
/*
** Function: PROSLIC_GPIOControl
**
** Description:
** Sets gpio of the proslic
*/
int Si3226x_GPIOControl (proslicChanType *pProslic,uInt8 *pGpioData, uInt8 read){
if (read)
*pGpioData = 0xf & ReadReg(pProHW,pProslic->channel,GPIO);
else{
WriteReg(pProHW,pProslic->channel,GPIO,(*pGpioData)|(ReadReg(pProHW,pProslic->channel,GPIO)&0xf0));
}
return 0;
}
/*
** Function: PROSLIC_MWI
**
** Description:
** implements message waiting indicator
*/
int Si3226x_MWI (proslicChanType *pProslic,uInt8 lampOn){
/*message waiting (neon flashing) requires modifications to vbath_expect and slope_vlim.
The old values are restored to turn off the lamp. We assume all channels set up the same.
During off-hook event lamp must be disabled manually. */
static int32 vbath_save = 0;
static int32 slope_vlim_save = 0;
uInt8 hkStat; int32 slope_vlim_tmp;
slope_vlim_tmp = ReadRAM(pProHW,pProslic->channel,SLOPE_VLIM);
Si3226x_ReadHookStatus(pProslic,&hkStat);
if (lampOn && (hkStat == PROSLIC_OFFHOOK) ) {/*cant neon flash during offhook*/
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT ("Si3226x MWI cannot operate offhook\n");
#endif
return RC_LINE_IN_USE;
}
if (lampOn) {
if (slope_vlim_tmp != 0x8000000L) { /*check we're not already on*/
vbath_save = ReadRAM(pProHW,pProslic->channel,VBATH_EXPECT);
slope_vlim_save = slope_vlim_tmp;
}
WriteRAM(pProHW,pProslic->channel,VBATH_EXPECT,0x7AE147AL);/*120V*/
WriteRAM(pProHW,pProslic->channel,SLOPE_VLIM,0x8000000L);
} else {
if (vbath_save != 0) { /*check we saved some valid value first*/
WriteRAM(pProHW,pProslic->channel,VBATH_EXPECT,vbath_save);
WriteRAM(pProHW,pProslic->channel,SLOPE_VLIM,slope_vlim_save);
}
}
return RC_NONE;
}
/*
** Function: PROSLIC_StartGenericTone
**
** Description:
** start tone generators
*/
int Si3226x_ToneGenStart (proslicChanType *pProslic,uInt8 timerEn){
uInt8 data;
data = ReadReg(pProHW,pProslic->channel,OCON);
data |= 0x11 + (timerEn ? 0x66 : 0);
WriteReg(pProHW,pProslic->channel,OCON,data);
return 0;
}
/*
** Function: PROSLIC_StopTone
**
** Description:
** Stops tone generators
**
** Input Parameters:
** pProslic: pointer to Proslic object
**
** Return:
** none
*/
int Si3226x_ToneGenStop (proslicChanType *pProslic){
uInt8 data;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x ToneGenStop\n");
#endif
data = ReadReg(pProHW,pProslic->channel,OCON);
data &= ~(0x77);
WriteReg(pProHW,pProslic->channel,OCON,data);
return 0;
}
/*
** Function: PROSLIC_StartRing
**
** Description:
** start ring generator
*/
int Si3226x_RingStart (proslicChanType *pProslic){
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x RingStart\n");
#endif
Si3226x_SetLinefeedStatus(pProslic,LF_RINGING);
return 0;
}
/*
** Function: PROSLIC_StopRing
**
** Description:
** Stops ring generator
*/
int Si3226x_RingStop (proslicChanType *pProslic){
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x RingStop\n");
#endif
Si3226x_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);
return 0;
}
/*
** Function: PROSLIC_EnableCID
**
** Description:
** enable fsk
*/
int Si3226x_EnableCID (proslicChanType *pProslic){
uInt8 data;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x EnableCID\n");
#endif
WriteReg(pProHW,pProslic->channel,OCON,0);
data = ReadReg(pProHW,pProslic->channel,OMODE);
data |= 0xA;
WriteReg(pProHW,pProslic->channel,OMODE,data);
WriteReg(pProHW,pProslic->channel,OCON,0x5);
return 0;
}
/*
** Function: PROSLIC_DisableCID
**
** Description:
** disable fsk
*/
int Si3226x_DisableCID (proslicChanType *pProslic){
uInt8 data;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x DisableCID\n");
#endif
WriteReg(pProHW,pProslic->channel,OCON,0);
data = ReadReg(pProHW,pProslic->channel,OMODE);
data &= ~(0x8);
WriteReg(pProHW,pProslic->channel,OMODE,data);
return 0;
}
/*
** Function: PROSLIC_SendCID
**
** Description:
** send fsk data
*/
int Si3226x_SendCID (proslicChanType *pProslic, uInt8 *buffer, uInt8 numBytes){
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x SendCID\n");
#endif
while (numBytes-- > 0){
WriteReg(pProHW,pProslic->channel,FSKDAT,*(buffer++));
}
return 0;
}
/*
** Function: PROSLIC_StartPCM
**
** Description:
** Starts PCM
*/
int Si3226x_PCMStart (proslicChanType *pProslic){
uInt8 data;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x PCMStart\n");
#endif
data = ReadReg(pProHW,pProslic->channel,PCMMODE);
data |= 0x10;
WriteReg(pProHW,pProslic->channel,PCMMODE,data);
return 0;
}
/*
** Function: PROSLIC_StopPCM
**
** Description:
** Disables PCM
*/
int Si3226x_PCMStop (proslicChanType *pProslic){
uInt8 data;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x PCMStop\n");
#endif
data = ReadReg(pProHW,pProslic->channel,PCMMODE);
data &= ~(0x10);
WriteReg(pProHW,pProslic->channel,PCMMODE,data);
return 0;
}
/*
** Function: PROSLIC_ReadDTMFDigit
**
** Description:
** Read DTMF digit (would be called after DTMF interrupt to collect digit)
*/
int Si3226x_DTMFReadDigit (proslicChanType *pProslic,uInt8 *pDigit){
*pDigit = ReadReg(pProHW,pProslic->channel,TONDTMF) & 0xf;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
LOGPRINT("Si3226x: DTMFReadDigit %d\n",*pDigit);
#endif
return 0;
}
/*
** Function: PROSLIC_PLLFreeRunStart
**
** Description:
** initiates pll free run mode
*/
int Si3226x_PLLFreeRunStart (proslicChanType *pProslic){
uInt8 tmp;
tmp = ReadReg(pProHW,pProslic->channel,ENHANCE);
WriteReg(pProHW,pProslic->channel,ENHANCE,tmp|0x4);
return 0;
}
/*
** Function: PROSLIC_PLLFreeRunStop
**
** Description:
** exit pll free run mode
*/
int Si3226x_PLLFreeRunStop (proslicChanType *pProslic){
uInt8 tmp;
tmp = ReadReg(pProHW,pProslic->channel,ENHANCE);
WriteReg(pProHW,pProslic->channel,ENHANCE,tmp&~(0x4));
return 0;
}
/*
** Function: PROSLIC_PulseMeterStart
**
** Description:
** start pulse meter tone
*/
int Si3226x_PulseMeterStart (proslicChanType *pProslic){
WriteReg(pProHW,pProslic->channel,PMCON,ReadReg(pProHW,pProslic->channel,PMCON) | (0x5));
return 0;
}
/*
** Function: PROSLIC_PulseMeterStop
**
** Description:
** stop pulse meter tone
*/
int Si3226x_PulseMeterStop (proslicChanType *pProslic){
WriteReg(pProHW,pProslic->channel,PMCON,ReadReg(pProHW,pProslic->channel,PMCON) & ~(0x5));
return 0;
}
/*
** Function: PROSLIC_dbgSetDCFeed
**
** Description:
** provisionary function for setting up
** dcfeed given desired open circuit voltage
** and loop current.
*/
int Si3226x_dbgSetDCFeed (proslicChanType *pProslic, uInt32 v_vlim_val, uInt32 i_ilim_val, int32 preset){
/* Note: * needs more descriptive return codes in the event of an out of range arguement */
uInt16 vslope = 160;
uInt16 rslope = 720;
uInt32 vscale1 = 1386;
uInt32 vscale2 = 1422; /* 1386x1422 = 1970892 broken down to minimize trunc err */
uInt32 iscale1 = 913;
uInt32 iscale2 = 334; /* 913x334 = 304942 */
uInt32 i_rfeed_val, v_rfeed_val, const_rfeed_val, i_vlim_val, const_ilim_val, v_ilim_val;
int32 signedVal;
/* Set Linefeed to open state before modifying DC Feed */
/* Assumptions must be made to minimize computations. This limits the
** range of available settings, but should be more than adequate for
** short loop applications.
**
** Assumtions:
**
** SLOPE_VLIM => 160ohms
** SLOPE_RFEED => 720ohms
** I_RFEED => 3*I_ILIM/4
**
** With these assumptions, the DC Feed parameters now become
**
** Inputs: V_VLIM, I_ILIM
** Constants: SLOPE_VLIM, SLOPE_ILIM, SLOPE_RFEED, SLOPE_DELTA1, SLOPE_DELTA2
** Outputs: V_RFEED, V_ILIM, I_VLIM, CONST_RFEED, CONST_ILIM
**
*/
/* Validate arguements */
if((i_ilim_val < 15)||(i_ilim_val > 45)) return 1; /* need error code */
if((v_vlim_val < 30)||(v_vlim_val > 52)) return 1; /* need error code */
/* Calculate voltages in mV and currents in uA */
v_vlim_val *= 1000;
i_ilim_val *= 1000;
/* I_RFEED */
i_rfeed_val = (3*i_ilim_val)/4;
/* V_RFEED */
v_rfeed_val = v_vlim_val - (i_rfeed_val*vslope)/1000;
/* V_ILIM */
v_ilim_val = v_rfeed_val - (rslope*(i_ilim_val - i_rfeed_val))/1000;
/* I_VLIM */
i_vlim_val = (v_vlim_val*1000)/4903;
/* CONST_RFEED */
signedVal = v_rfeed_val * (i_ilim_val - i_rfeed_val);
signedVal /= (v_rfeed_val - v_ilim_val);
signedVal = i_rfeed_val + signedVal;
/* signedVal in uA here */
signedVal *= iscale1;
signedVal /= 100;
signedVal *= iscale2;
signedVal /= 10;
if(signedVal < 0)
{
const_rfeed_val = (signedVal)+ (1L<<29);
}
else
{
const_rfeed_val = signedVal & 0x1FFFFFFF;
}
/* CONST_ILIM */
const_ilim_val = i_ilim_val;
/* compute RAM values */
v_vlim_val *= vscale1;
v_vlim_val /= 100;
v_vlim_val *= vscale2;
v_vlim_val /= 10;
v_rfeed_val *= vscale1;
v_rfeed_val /= 100;
v_rfeed_val *= vscale2;
v_rfeed_val /= 10;
v_ilim_val *= vscale1;
v_ilim_val /= 100;
v_ilim_val *= vscale2;
v_ilim_val /= 10;
const_ilim_val *= iscale1;
const_ilim_val /= 100;
const_ilim_val *= iscale2;
const_ilim_val /= 10;
i_vlim_val *= iscale1;
i_vlim_val /= 100;
i_vlim_val *= iscale2;
i_vlim_val /= 10;
Si3226x_DCfeed_Presets[preset].slope_vlim = 0x18842BD7L;
Si3226x_DCfeed_Presets[preset].slope_rfeed = 0x1E8886DEL;
Si3226x_DCfeed_Presets[preset].slope_ilim = 0x40A0E0L;
Si3226x_DCfeed_Presets[preset].delta1 = 0x1EABA1BFL;
Si3226x_DCfeed_Presets[preset].delta2 = 0x1EF744EAL;
Si3226x_DCfeed_Presets[preset].v_vlim = v_vlim_val;
Si3226x_DCfeed_Presets[preset].v_rfeed = v_rfeed_val;
Si3226x_DCfeed_Presets[preset].v_ilim = v_ilim_val;
Si3226x_DCfeed_Presets[preset].const_rfeed = const_rfeed_val;
Si3226x_DCfeed_Presets[preset].const_ilim = const_ilim_val;
Si3226x_DCfeed_Presets[preset].i_vlim = i_vlim_val;
return 0;
}
/*
** Function: PROSLIC_dbgSetDCFeedVopen
**
** Description:
** provisionary function for setting up
** dcfeed given desired open circuit voltage.
** Entry I_ILIM value will be used.
*/
int Si3226x_dbgSetDCFeedVopen (proslicChanType *pProslic, uInt32 v_vlim_val, int32 preset)
{
uInt32 i_ilim_val;
uInt32 iscale1 = 913;
uInt32 iscale2 = 334; /* 913x334 = 304942 */
/* Read present CONST_ILIM value */
i_ilim_val = Si3226x_DCfeed_Presets[preset].const_ilim;
i_ilim_val /= iscale2;
i_ilim_val /= iscale1;
return Si3226x_dbgSetDCFeed(pProslic,v_vlim_val,i_ilim_val,preset);
}
/*
** Function: PROSLIC_dbgSetDCFeedIloop
**
** Description:
** provisionary function for setting up
** dcfeed given desired loop current.
** Entry V_VLIM value will be used.
*/
int Si3226x_dbgSetDCFeedIloop (proslicChanType *pProslic, uInt32 i_ilim_val, int32 preset)
{
uInt32 v_vlim_val;
uInt32 vscale1 = 1386;
uInt32 vscale2 = 1422; /* 1386x1422 = 1970892 broken down to minimize trunc err */
/* Read present V_VLIM value */
v_vlim_val = Si3226x_DCfeed_Presets[preset].v_vlim;
v_vlim_val /= vscale2;
v_vlim_val /= vscale1;
return Si3226x_dbgSetDCFeed(pProslic,v_vlim_val,i_ilim_val, preset);
}
typedef struct
{
uInt8 freq;
ramData ringfr; /* trise scale for trap */
uInt32 ampScale;
} ProSLIC_SineRingFreqLookup;
typedef struct
{
uInt8 freq;
ramData rtacth;
ramData rtper;
ramData rtdb;
} ProSLIC_SineRingtripLookup;
typedef struct
{
uInt8 freq;
uInt16 cfVal[6];
} ProSLIC_TrapRingFreqLookup;
typedef struct
{
uInt8 freq;
ramData rtper;
ramData rtdb;
uInt32 rtacth[6];
} ProSLIC_TrapRingtripLookup;
/*
** Function: PROSLIC_dbgRingingSetup
**
** Description:
** Provisionary function for setting up
** Ring type, frequency, amplitude and dc offset.
** Main use will be by peek/poke applications.
*/
int Si3226x_dbgSetRinging (proslicChanType *pProslic, ProSLIC_dbgRingCfg *ringCfg, int preset){
int errVal,i=0;
uInt32 vScale = 1608872L; /* (2^28/170.25)*((100+4903)/4903) */
ramData dcdcVminTmp;
const ProSLIC_SineRingFreqLookup sineRingFreqTable[] =
/* Freq RINGFR, vScale */
{{15, 0x7F6E930L, 18968L},
{16, 0x7F5A8E0L, 20234L},
{20, 0x7EFD9D5L, 25301L},
{22, 0x7EC770AL, 27843L},
{23, 0x7EAA6E2L, 29113L},
{25, 0x7E6C925L, 31649L},
{30, 0x7DBB96BL, 38014L},
{34, 0x7D34155L, 42270L}, /* Actually 33.33Hz */
{35, 0x7CEAD72L, 44397L},
{40, 0x7BFA887L, 50802L},
{45, 0x7AEAE74L, 57233L},
{50, 0x79BC384L, 63693L},
{0,0,0}}; /* terminator */
const ProSLIC_SineRingtripLookup sineRingtripTable[] =
/* Freq rtacth */
{ {15, 11440000L, 0x6A000L, 0x4000L },
{16, 10810000L, 0x64000L, 0x4000L },
{20, 8690000L, 0x50000L, 0x8000L },
{22, 7835000L, 0x48000L, 0x8000L },
{23, 7622000L, 0x46000L, 0x8000L },
{25, 6980000L, 0x40000L, 0xA000L },
{30, 5900000L, 0x36000L, 0xA000L },
{34, 10490000L, 0x60000L, 0x6000L }, /* Actually 33.33 */
{35, 10060000L, 0x5C000L, 0x6000L },
{40, 8750000L, 0x50000L, 0x8000L },
{45, 7880000L, 0x48000L, 0x8000L },
{50, 7010000L, 0x40000L, 0xA000L },
{0,0L}}; /* terminator */
const ProSLIC_TrapRingFreqLookup trapRingFreqTable[] =
/* Freq multCF11 multCF12 multCF13 multCF14 multCF15 multCF16*/
{
{15, {69,122, 163, 196, 222,244}},
{16, {65,115, 153, 184, 208,229}},
{20, {52,92, 122, 147, 167,183}},
{22, {47,83, 111, 134, 152,166}},
{23, {45,80, 107, 128, 145,159}},
{25, {42,73, 98, 118, 133,146}},
{30, {35,61, 82, 98, 111,122}},
{34, {31,55, 73, 88, 100,110}},
{35, {30,52, 70, 84, 95,104}},
{40, {26,46, 61, 73, 83,91}},
{45, {23,41, 54, 65, 74,81}},
{50, {21,37, 49, 59, 67,73}},
{0,{0L,0L,0L,0L}} /* terminator */
};
const ProSLIC_TrapRingtripLookup trapRingtripTable[] =
/* Freq rtper rtdb rtacthCR11 rtacthCR12 rtacthCR13 rtacthCR14 rtacthCR15 rtacthCR16*/
{
{15, 0x6A000L, 0x4000L, {16214894L, 14369375L, 12933127L, 11793508L, 10874121L, 10121671L}},
{16, 0x64000L, 0x4000L, {15201463L, 13471289L, 12124806L, 11056414L, 10194489L, 9489067L}},
{20, 0x50000L, 0x6000L, {12161171L, 10777031L, 9699845L, 8845131L, 8155591L, 7591253L}},
{22, 0x48000L, 0x6000L, {11055610L, 9797301L, 8818041L, 8041028L, 7414174L, 6901139L}},
{23, 0x46000L, 0x6000L, {10574931L, 9371331L, 8434648L, 7691418L, 7091818L, 6601090L}},
{25, 0x40000L, 0x8000L, {9728937L, 8621625L, 7759876L, 7076105L, 6524473L, 6073003L}},
{30, 0x36000L, 0x8000L, {8107447L, 7184687L, 6466563L, 5896754L, 5437061L, 5060836L}},
{34, 0x60000L, 0x6000L, {7297432L, 6466865L, 5820489L, 5307609L, 4893844L, 4555208L}},
{35, 0x5C000L, 0x6000L, {6949240L, 6158303L, 5542769L, 5054361L, 4660338L, 4337859L}},
{40, 0x50000L, 0x6000L, {6080585L, 5388516L, 4849923L, 4422565L, 4077796L, 3795627L}},
{45, 0x48000L, 0x6000L, {5404965L, 4789792L, 4311042L, 3931169L, 3624707L, 3373890L}},
{50, 0x40000L, 0x8000L, {4864468L, 4310812L, 3879938L, 3538052L, 3262236L, 3036501L}},
{0,0x0L, 0x0L, {0L,0L,0L,0L}} /* terminator */
};
errVal = 0;
switch(ringCfg->ringtype)
{
case ProSLIC_RING_SINE:
i=0;
do
{
if(sineRingFreqTable[i].freq >= ringCfg->freq)
{
break;
}
i++;
} while (sineRingFreqTable[i].freq);
/* Set to maximum value if exceeding maximum value from table */
if(sineRingFreqTable[i].freq == 0)
{
i--;
errVal = 1;
}
/* Update RINGFR RINGAMP, RINGOFFSET, and RINGCON */
Si3226x_Ring_Presets[preset].freq = sineRingFreqTable[i].ringfr;
Si3226x_Ring_Presets[preset].amp = ringCfg->amp * sineRingFreqTable[i].ampScale;
Si3226x_Ring_Presets[preset].offset = ringCfg->offset * vScale;
Si3226x_Ring_Presets[preset].phas = 0L;
/* Don't alter anything in RINGCON other than clearing the TRAP bit */
Si3226x_Ring_Presets[preset].ringcon &= 0xFE;
Si3226x_Ring_Presets[preset].rtper = sineRingtripTable[i].rtper;
Si3226x_Ring_Presets[preset].rtacdb = sineRingtripTable[i].rtdb;
Si3226x_Ring_Presets[preset].rtdcdb = sineRingtripTable[i].rtdb;
Si3226x_Ring_Presets[preset].rtdcth = 0xFFFFFFFL;
Si3226x_Ring_Presets[preset].rtacth = sineRingtripTable[i].rtacth;
break;
case ProSLIC_RING_TRAP_CF11:
case ProSLIC_RING_TRAP_CF12:
case ProSLIC_RING_TRAP_CF13:
case ProSLIC_RING_TRAP_CF14:
case ProSLIC_RING_TRAP_CF15:
case ProSLIC_RING_TRAP_CF16:
i=0;
do
{
if(trapRingFreqTable[i].freq >= ringCfg->freq)
{
break;
}
i++;
} while (trapRingFreqTable[i].freq);
/* Set to maximum value if exceeding maximum value from table */
if(trapRingFreqTable[i].freq == 0)
{
i--;
errVal = 1;
}
/* Update RINGFR RINGAMP, RINGOFFSET, and RINGCON */
Si3226x_Ring_Presets[preset].amp = ringCfg->amp * vScale;
Si3226x_Ring_Presets[preset].freq = Si3226x_Ring_Presets[preset].amp/trapRingFreqTable[i].cfVal[ringCfg->ringtype];
Si3226x_Ring_Presets[preset].offset = ringCfg->offset * vScale;
Si3226x_Ring_Presets[preset].phas = 262144000L/trapRingFreqTable[i].freq;
/* Don't alter anything in RINGCON other than setting the TRAP bit */
Si3226x_Ring_Presets[preset].ringcon |= 0x01;
/* RTPER and debouce timers */
Si3226x_Ring_Presets[preset].rtper = trapRingtripTable[i].rtper;
Si3226x_Ring_Presets[preset].rtacdb = trapRingtripTable[i].rtdb;
Si3226x_Ring_Presets[preset].rtdcdb = trapRingtripTable[i].rtdb;
Si3226x_Ring_Presets[preset].rtdcth = 0xFFFFFFFL;
Si3226x_Ring_Presets[preset].rtacth = trapRingtripTable[i].rtacth[ringCfg->ringtype];
break;
}
/*
** DCDC tracking sluggish under light load at higher ring freq.
** Reduce tracking depth above 40Hz. This should have no effect
** if using the Buck-Boost architecture.
*/
if((sineRingFreqTable[i].freq >= 40)||(Si3226x_General_Configuration.bomOpt == BO_DCDC_BUCK_BOOST))
{
dcdcVminTmp = ringCfg->amp + ringCfg->offset;
dcdcVminTmp *= 1000;
dcdcVminTmp *= SCALE_V_MADC;
Si3226x_Ring_Presets[preset].vbat_track_min_rng = dcdcVminTmp;
}
else
{
Si3226x_Ring_Presets[preset].vbat_track_min_rng = 0x1800000L;
}
return errVal;
}
typedef struct
{
int32 gain;
uInt32 scale;
} ProSLIC_GainScaleLookup;
#define GAIN_MAX 6
#define GAIN_MIN -30
static int Si3226x_dbgSetGain (proslicChanType *pProslic, int32 gain, int impedance_preset, int tx_rx_sel){
int errVal = 0;
int32 i;
int32 gain_pga, gain_eq;
const ProSLIC_GainScaleLookup gainScaleTable[] = /* gain, scale=10^(gain/20) */
{
{-30, 32},
{-29, 35},
{-28, 40},
{-27, 45},
{-26, 50},
{-25, 56},
{-24, 63},
{-23, 71},
{-22, 79},
{-21, 89},
{-20, 100},
{-19, 112},
{-18, 126},
{-17, 141},
{-16, 158},
{-15, 178},
{-14, 200},
{-13, 224},
{-12, 251},
{-11, 282},
{-10, 316},
{-9, 355},
{-8, 398},
{-7, 447},
{-6, 501},
{-5, 562},
{-4, 631},
{-3, 708},
{-2, 794},
{-1, 891},
{0, 1000},
{1, 1122},
{2, 1259},
{3, 1413},
{4, 1585},
{5, 1778},
{6, 1995},
{0xff,0} /* terminator */
};
/*
** 5.4.0 - Removed relative gain scaling. to support automatic adjustment based on
** gain plan provided in txgain_db and rxgain_db. It is presumed that all
** coefficients were generated for 0dB/0dB gain and the txgain_db and rxgain_db
** parameters will be used to scale the gain using the existing gain provisioning
** infrastructure when the zsynth preset is loaded. This function will ignore
** the txgain_db and rxgain_db parameters and scale absolute gain presuming a
** 0dB/0dB coefficient set.
*/
/*
** 6.0.0 - Modifying where gain/attenuation is placed to minimize clipping.
**
** RX Path: -30dB < gain < 0dB - All in RXACGAIN
** 0dB < gain < 6dB - All in RXACEQ
**
** TX Path: -30dB < gain < 0dB - All in TXACEQ
** 0dB < gain < 6dB - All in TXACGAIN
*/
/* Test against max gain */
if (gain > GAIN_MAX)
{
errVal = RC_GAIN_OUT_OF_RANGE;
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("ProSLIC : Si3226x : dbgSetGain : Gain %d out of range\n",gain);
}
#endif
gain = GAIN_MAX; /* Clamp to maximum */
}
/* Test against min gain */
if (gain < GAIN_MIN)
{
errVal = RC_GAIN_OUT_OF_RANGE;
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("ProSLIC : Si3226x : dbgSetGain : Gain %d out of range\n",gain);
}
#endif
gain = GAIN_MIN; /* Clamp to minimum */
}
/* Distribute gain */
if(gain == 0)
{
gain_pga = 0;
gain_eq = 0;
}
else if(gain > 0)
{
if(tx_rx_sel == TXACGAIN_SEL)
{
gain_pga = gain;
gain_eq = 0;
}
else
{
gain_pga = 0;
gain_eq = gain;
}
}
else
{
if(tx_rx_sel == TXACGAIN_SEL)
{
gain_pga = 0;
gain_eq = gain;
}
else
{
gain_pga = gain;
gain_eq = 0;
}
}
/*
** Lookup PGA Appopriate PGA Gain
*/
i=0;
do
{
if(gainScaleTable[i].gain >= gain_pga)
{
break;
}
i++;
} while (gainScaleTable[i].gain!=0xff);
/* Set to maximum value if exceeding maximum value from table */
if(gainScaleTable[i].gain == 0xff)
{
i--;
errVal = RC_GAIN_DELTA_TOO_LARGE;
}
if(tx_rx_sel == TXACGAIN_SEL)
{
Si3226x_audioGain_Presets[0].acgain = (Si3226x_Impedance_Presets[impedance_preset].txgain/1000)*gainScaleTable[i].scale;
}
else
{
Si3226x_audioGain_Presets[1].acgain = (Si3226x_Impedance_Presets[impedance_preset].rxgain/1000)*gainScaleTable[i].scale;
}
/*
** Lookup EQ Gain
*/
i=0;
do
{
if(gainScaleTable[i].gain >= gain_eq)
{
break;
}
i++;
} while (gainScaleTable[i].gain!=0xff);
/* Set to maximum value if exceeding maximum value from table */
if(gainScaleTable[i].gain == 0xff)
{
i--;
errVal = RC_GAIN_DELTA_TOO_LARGE;
}
if(tx_rx_sel == TXACGAIN_SEL)
{
/*sign extend negative numbers*/
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 |= 0xf0000000L;
Si3226x_audioGain_Presets[0].aceq_c0 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0/1000)*gainScaleTable[i].scale;
Si3226x_audioGain_Presets[0].aceq_c1 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1/1000)*gainScaleTable[i].scale;
Si3226x_audioGain_Presets[0].aceq_c2 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2/1000)*gainScaleTable[i].scale;
Si3226x_audioGain_Presets[0].aceq_c3 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3/1000)*gainScaleTable[i].scale;
}
else
{
/*sign extend negative numbers*/
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 |= 0xf0000000L;
Si3226x_audioGain_Presets[1].aceq_c0 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0/1000)*gainScaleTable[i].scale;
Si3226x_audioGain_Presets[1].aceq_c1 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1/1000)*gainScaleTable[i].scale;
Si3226x_audioGain_Presets[1].aceq_c2 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2/1000)*gainScaleTable[i].scale;
Si3226x_audioGain_Presets[1].aceq_c3 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3/1000)*gainScaleTable[i].scale;
}
return errVal;
}
/* Same as Si3226x_dbgSetGain() except gain is expressed in dB*10 to achieve 0.1dB resolution */
static int Si3226x_dbgSetGainHiRes (proslicChanType *pProslic, int32 gain, int impedance_preset, int tx_rx_sel){
int errVal = 0;
int32 i;
int32 coarseGainIndex, fineGainIndex;
int32 gain_pga, gain_eq;
int32 coarseGain, fineGain;
int32 tmp;
const ProSLIC_GainScaleLookup coarseGainScaleTable[] = /* gain, scale=10^(gain/20) */
{
{-30, 32},
{-29, 35},
{-28, 40},
{-27, 45},
{-26, 50},
{-25, 56},
{-24, 63},
{-23, 71},
{-22, 79},
{-21, 89},
{-20, 100},
{-19, 112},
{-18, 126},
{-17, 141},
{-16, 158},
{-15, 178},
{-14, 200},
{-13, 224},
{-12, 251},
{-11, 282},
{-10, 316},
{-9, 355},
{-8, 398},
{-7, 447},
{-6, 501},
{-5, 562},
{-4, 631},
{-3, 708},
{-2, 794},
{-1, 891},
{0, 1000},
{1, 1122},
{2, 1259},
{3, 1413},
{4, 1585},
{5, 1778},
{6, 1995},
{0xff,0} /* terminator */
};
const ProSLIC_GainScaleLookup fineGainScaleTable[] = /* gain, scale=10^(gain/20) */
{
{-9, 902},
{-8, 912},
{-7, 923},
{-6, 933},
{-5, 944},
{-4, 955},
{-3, 966},
{-2, 977},
{-1, 989},
{0, 1000},
{1, 1012},
{2, 1023},
{3, 1035},
{4, 1047},
{5, 1059},
{6, 1072},
{7, 1084},
{8, 1096},
{9, 1109},
{0xff,0} /* terminator */
};
/*
** 6.0.0 - Modifying where gain/attenuation is placed to minimize clipping.
**
** RX Path: -30dB < gain < 0dB - All in RXACGAIN
** 0dB < gain < 6dB - All in RXACEQ
**
** TX Path: -30dB < gain < 0dB - All in TXACEQ
** 0dB < gain < 6dB - All in TXACGAIN
**
** 6.2.1 - Added option for fine gain adjust. All fine adjustment done
** in RXACGAIN and TXACEQ
*/
/* Test against max gain */
if (gain > (GAIN_MAX*10L))
{
errVal = RC_GAIN_OUT_OF_RANGE;
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("ProSLIC : Si3226x : dbgSetGain : Gain %d dB*10 out of range\n",gain);
}
#endif
gain = (GAIN_MAX*10L); /* Clamp to maximum */
}
/* Test against min gain */
if (gain < (GAIN_MIN*10L))
{
errVal = RC_GAIN_OUT_OF_RANGE;
#ifdef ENABLE_DEBUG
if(pProslic->debugMode)
{
LOGPRINT("ProSLIC : Si3226x : dbgSetGain : Gain %d dB*10 out of range\n",gain);
}
#endif
gain = (GAIN_MIN*10); /* Clamp to minimum */
}
/* Distribute gain */
coarseGain = gain/10L;
fineGain = gain - (coarseGain*10L);
/* Distribute coarseGain */
if(coarseGain == 0)
{
gain_pga = 0;
gain_eq = 0;
}
else if(coarseGain > 0)
{
if(tx_rx_sel == TXACGAIN_SEL)
{
gain_pga = coarseGain;
gain_eq = 0;
}
else
{
gain_pga = 0;
gain_eq = coarseGain;
}
}
else
{
if(tx_rx_sel == TXACGAIN_SEL)
{
gain_pga = 0;
gain_eq = coarseGain;
}
else
{
gain_pga = coarseGain;
gain_eq = 0;
}
}
/*
** Lookup PGA Appopriate PGA Gain
*/
i=0;
do
{
if(coarseGainScaleTable[i].gain >= gain_pga)
{
break;
}
i++;
} while (coarseGainScaleTable[i].gain!=0xff);
/* Set to maximum value if exceeding maximum value from table */
if(coarseGainScaleTable[i].gain == 0xff)
{
i--;
errVal = RC_GAIN_DELTA_TOO_LARGE;
}
coarseGainIndex = i; /* Store coarse index */
/* Find fineGain */
i = 0;
do
{
if(fineGainScaleTable[i].gain >= fineGain)
{
break;
}
i++;
} while (fineGainScaleTable[i].gain!=0xff);
/* Set to maximum value if exceeding maximum value from table */
if(fineGainScaleTable[i].gain == 0xff)
{
i--;
errVal = RC_GAIN_DELTA_TOO_LARGE;
}
fineGainIndex = i;
if(tx_rx_sel == TXACGAIN_SEL)
{
Si3226x_audioGain_Presets[0].acgain = ((Si3226x_Impedance_Presets[impedance_preset].txgain/1000L)*coarseGainScaleTable[coarseGainIndex].scale); /* /1000L * fineGainScaleTable[fineGainIndex].scale; */
}
else
{
Si3226x_audioGain_Presets[1].acgain = ((Si3226x_Impedance_Presets[impedance_preset].rxgain/1000L)*coarseGainScaleTable[coarseGainIndex].scale)/1000L * fineGainScaleTable[fineGainIndex].scale;
}
/*
** Lookup EQ Gain
*/
i=0;
do
{
if(coarseGainScaleTable[i].gain >= gain_eq)
{
break;
}
i++;
} while (coarseGainScaleTable[i].gain!=0xff);
/* Set to maximum value if exceeding maximum value from table */
if(coarseGainScaleTable[i].gain == 0xff)
{
i--;
errVal = RC_GAIN_DELTA_TOO_LARGE;
}
coarseGainIndex = i; /* Store coarse index */
if(tx_rx_sel == TXACGAIN_SEL)
{
/*sign extend negative numbers*/
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 |= 0xf0000000L;
tmp = (((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0/1000L)*coarseGainScaleTable[coarseGainIndex].scale);
tmp = tmp / (int32)1000L;
tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
Si3226x_audioGain_Presets[0].aceq_c0 = tmp;
tmp = (((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1/1000L)*coarseGainScaleTable[coarseGainIndex].scale);
tmp = tmp / (int32)1000L;
tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
Si3226x_audioGain_Presets[0].aceq_c1 = tmp;
tmp = (((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2/1000L)*coarseGainScaleTable[coarseGainIndex].scale);
tmp = tmp / (int32)1000L;
tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
Si3226x_audioGain_Presets[0].aceq_c2 = tmp;
tmp = (((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3/1000L)*coarseGainScaleTable[coarseGainIndex].scale);
tmp = tmp / (int32)1000L;
tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
Si3226x_audioGain_Presets[0].aceq_c3 = tmp;
}
else
{
/*sign extend negative numbers*/
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 |= 0xf0000000L;
if (Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 & 0x10000000L)
Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 |= 0xf0000000L;
Si3226x_audioGain_Presets[1].aceq_c0 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0/1000)*coarseGainScaleTable[i].scale;
Si3226x_audioGain_Presets[1].aceq_c1 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1/1000)*coarseGainScaleTable[i].scale;
Si3226x_audioGain_Presets[1].aceq_c2 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2/1000)*coarseGainScaleTable[i].scale;
Si3226x_audioGain_Presets[1].aceq_c3 = ((int32)Si3226x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3/1000)*coarseGainScaleTable[i].scale;
}
return errVal;
}
/*
** Function: PROSLIC_dbgSetTXGain
**
** Description:
** Provisionary function for setting up
** TX gain
*/
int Si3226x_dbgSetTXGain (proslicChanType *pProslic, int32 gain, int impedance_preset, int audio_gain_preset){
#ifdef ENABLE_HIRES_GAIN
return Si3226x_dbgSetGainHiRes(pProslic,gain,impedance_preset,audio_gain_preset);
#else
return Si3226x_dbgSetGain(pProslic,gain,impedance_preset,audio_gain_preset);
#endif
}
/*
** Function: PROSLIC_dbgSetRXGain
**
** Description:
** Provisionary function for setting up
** RX gain
*/
int Si3226x_dbgSetRXGain (proslicChanType *pProslic, int32 gain, int impedance_preset, int audio_gain_preset){
#ifdef ENABLE_HIRES_GAIN
return Si3226x_dbgSetGainHiRes(pProslic,gain,impedance_preset,audio_gain_preset);
#else
return Si3226x_dbgSetGain(pProslic,gain,impedance_preset,audio_gain_preset);
#endif
}
/*
** Function: Si3226x_LineMonitor
**
** Description:
** Monitor line voltages and currents
*/
int Si3226x_LineMonitor(proslicChanType *pProslic, proslicMonitorType *monitor)
{
if(pProslic->channelEnable)
{
monitor->vtr = ReadRAM(pProHW,pProslic->channel,VDIFF_FILT);
if(monitor->vtr & 0x10000000L)
monitor->vtr |= 0xf0000000L;
monitor->vtr /= SCALE_V_MADC;
monitor->vtip = ReadRAM(pProHW,pProslic->channel,VTIP);
if(monitor->vtip & 0x10000000L)
monitor->vtip |= 0xf0000000L;
monitor->vtip /= SCALE_V_MADC;
monitor->vring = ReadRAM(pProHW,pProslic->channel,VRING);
if(monitor->vring & 0x10000000L)
monitor->vring |= 0xf0000000L;
monitor->vring /= SCALE_V_MADC;
monitor->vbat = ReadRAM(pProHW,pProslic->channel,MADC_VBAT);
if(monitor->vbat & 0x10000000L)
monitor->vbat |= 0xf0000000L;
monitor->vbat /= SCALE_V_MADC;
monitor->itr = ReadRAM(pProHW,pProslic->channel,MADC_ILOOP);
if(monitor->itr & 0x10000000L)
monitor->itr |= 0xf0000000L;
monitor->itr /= SCALE_I_MADC;
monitor->itip = ReadRAM(pProHW,pProslic->channel,MADC_ITIP);
if(monitor->itip & 0x10000000L)
monitor->itip |= 0xf0000000L;
monitor->itip /= SCALE_I_MADC;
monitor->iring = ReadRAM(pProHW,pProslic->channel,MADC_IRING);
if(monitor->iring & 0x10000000L)
monitor->iring |= 0xf0000000L;
monitor->iring /= SCALE_I_MADC;
monitor->ilong = ReadRAM(pProHW,pProslic->channel,MADC_ILONG);
if(monitor->ilong & 0x10000000L)
monitor->ilong |= 0xf0000000L;
monitor->ilong /= SCALE_I_MADC;
}
return 0;
}
/*
** Function: Si3226x_AudioGainSetup
**
** Description:
** Set audio gain of RX and TX paths - presumed that
** all zsynth coefficient presets are 0dB
**
** Presumes that passed impedance preset has already been
** loaded via ProSLIC_ZsythSetup()
*/
int Si3226x_AudioGainSetup(proslicChanType *pProslic, int32 rxgain, int32 txgain, int preset)
{
Si3226x_dbgSetTXGain(pProslic,txgain,preset,0);
Si3226x_dbgSetRXGain(pProslic,rxgain,preset,1);
Si3226x_TXAudioGainSetup(pProslic,0);
Si3226x_RXAudioGainSetup(pProslic,1);
return 0;
}
/*
** Function: Si3226x_PSTNCheck
**
** Description:
** Continuous monitoring of longitudinal current.
** If an average of N samples exceed avgThresh or a
** single sample exceeds singleThresh, the linefeed
** is forced into the open state.
**
** This protects the port from connecting to a live
** pstn line (faster than power alarm).
**
** TODO: need error handling
*/
int Si3226x_PSTNCheck (proslicChanType *pProslic,proslicPSTNCheckObjType *pPSTNCheck)
{
uInt8 i;
/* Adjust buffer index */
if(pPSTNCheck->count >= pPSTNCheck->samples)
{
pPSTNCheck->buffFull = TRUE;
pPSTNCheck->count = 0; /* reset buffer ptr */
}
/* Read next sample */
pPSTNCheck->ilong[pPSTNCheck->count] = ReadRAM(pProHW,pProslic->channel,MADC_ILONG);
if(pPSTNCheck->ilong[pPSTNCheck->count] & 0x10000000L)
pPSTNCheck->ilong[pPSTNCheck->count] |= 0xf0000000L;
pPSTNCheck->ilong[pPSTNCheck->count] /= SCALE_I_MADC;
/* Monitor magnitude only */
if(pPSTNCheck->ilong[pPSTNCheck->count] < 0)
pPSTNCheck->ilong[pPSTNCheck->count] = -pPSTNCheck->ilong[pPSTNCheck->count];
/* Quickly test for single measurement violation */
if(pPSTNCheck->ilong[pPSTNCheck->count] > pPSTNCheck->singleThresh)
return 1; /* fail */
/* Average once buffer is full */
if(pPSTNCheck->buffFull == TRUE)
{
pPSTNCheck->avgIlong = 0;
for(i=0;i<pPSTNCheck->samples; i++)
{
pPSTNCheck->avgIlong += pPSTNCheck->ilong[i];
}
pPSTNCheck->avgIlong /= pPSTNCheck->samples;
if(pPSTNCheck->avgIlong > pPSTNCheck->avgThresh)
{
/* reinit obj and return fail */
pPSTNCheck->count = 0;
pPSTNCheck->buffFull = FALSE;
return 1;
}
else
{
pPSTNCheck->count++;
return 0;
}
}
else
{
pPSTNCheck->count++;
return 0;
}
}
/*
** Function: Si3226x_SetPwrsaveMode
**
** Description:
** Enable or disable powersave mode
**
** Returns:
** RC_NONE
*/
int Si3226x_SetPowersaveMode (proslicChanType *pProslic, int pwrsave)
{
uInt8 regData;
if(pProslic->channelType != PROSLIC) {
return RC_NONE; /* Ignore DAA channels */
}
regData = ReadReg(pProHW,pProslic->channel, ENHANCE);
if(pwrsave == PWRSAVE_DISABLE)
{
regData &= 0x07;
}
else
{
regData |= 0x30;
}
WriteReg(pProHW,pProslic->channel, ENHANCE, regData);
return RC_NONE;
}
/*
** Function: delay_poll
**
** Description:
** Delay function called within PSTN detection functions
**
** Return Value:
** none
*/
#ifdef PSTN_DET_ENABLE
static void Si3226x_polled_delay(proslicTestStateType *pState, unsigned short delay)
{
unsigned short delayCount;
if((delay/PSTN_DET_POLL_RATE) < 2)
delayCount = 0;
else
delayCount = (delay/PSTN_DET_POLL_RATE) - 2;
pState->waitIterations++;
if((pState->waitIterations == delayCount) || (delayCount == 0))
{
pState->waitIterations = 0;
pState->stage++;
}
}
#endif
/*
** Function: Si3226x_GetRAMScale
**
** Description:
** Read scale factor for passed RAM location
**
** Return Value:
** int32 scale
*/
static int32 Si3226x_GetRAMScale(uInt16 addr)
{
int32 scale;
switch(addr)
{
case MADC_ILOOP:
case MADC_ITIP:
case MADC_IRING:
case MADC_ILONG:
scale = SCALE_I_MADC;
break;
case MADC_VTIPC:
case MADC_VRINGC:
case MADC_VBAT:
case MADC_VLONG:
case VDIFF_SENSE:
case VDIFF_FILT:
case VDIFF_COARSE:
case VTIP:
case VRING:
scale = SCALE_V_MADC;
break;
default:
scale = 1;
break;
}
return scale;
}
/*
** Function: Si3226x_ReadMADCScaled
**
** Description:
** Read MADC (or other sensed voltages/currents) and
** return scaled value in int32 format.
**
** Return Value:
** int32 voltage in mV or
** int32 current in uA
*/
int32 Si3226x_ReadMADCScaled(proslicChanType_ptr pProslic,uInt16 addr, int32 scale)
{
int32 data;
/*
** Read 29-bit RAM and sign extend to 32-bits
*/
data = ReadRAM(pProHW,pProslic->channel,addr);
if(data & 0x10000000L)
data |= 0xF0000000L;
/*
** Scale to provided value, or use defaults if scale = 0
*/
if(scale == 0)
scale = Si3226x_GetRAMScale(addr);
data /= scale;
return data;
}
#ifdef PSTN_DET_ENABLE
/*
** Function: abs_int32
**
** Description:
** abs implementation for int32 type
*/
static int32 abs_int32(int32 a)
{
if(a < 0)
return -1*a;
return a;
}
/*
** Function: Si3226x_DiffPSTNCheck
**
** Description:
** Monitor for excessive longitudinal current, which
** would be present if a live pstn line was connected
** to the port.
**
** Returns:
** RC_NONE - test in progress
** RC_COMPLETE_NO_ERR - test complete, no alarms or errors
** RC_PSTN_OPEN_FEMF - test detected foreign voltage
**
*/
int Si3226x_DiffPSTNCheck (proslicChanType *pProslic, proslicDiffPSTNCheckObjType *pPSTNCheck){
uInt8 loop_status;
int i;
if(pProslic->channelType != PROSLIC) {
return RC_CHANNEL_TYPE_ERR; /* Ignore DAA channels */
}
switch(pPSTNCheck->pState.stage)
{
case 0:
/* Optional OPEN foreign voltage measurement - only execute if LCS = 0 */
/* Disable low power mode */
pPSTNCheck->enhanceRegSave = ReadReg(pProHW,pProslic->channel,ENHANCE);
if(pProslic->deviceId->chipRev != 0) { /* must stay in pwrsave mode on rev A */
WriteReg(pProHW,pProslic->channel, ENHANCE, pPSTNCheck->enhanceRegSave&0x07); /* Disable powersave */
}
pPSTNCheck->vdiff1_avg = 0;
pPSTNCheck->vdiff2_avg = 0;
pPSTNCheck->iloop1_avg = 0;
pPSTNCheck->iloop2_avg = 0;
pPSTNCheck->return_status = RC_COMPLETE_NO_ERR;
/* Do OPEN state hazardous voltage measurement if enabled and ONHOOK */
Si3226x_ReadHookStatus(pProslic,&loop_status);
if((loop_status == ONHOOK)&&(pPSTNCheck->femf_enable == 1))
pPSTNCheck->pState.stage++;
else
pPSTNCheck->pState.stage = 10;
return RC_NONE;
case 1:
/* Change linefeed to OPEN state for HAZV measurement, setup coarse sensors */
pPSTNCheck->lfstate_entry = ReadReg(pProHW,pProslic->channel, LINEFEED);
ProSLIC_SetLinefeedStatus(pProslic,LF_OPEN);
pPSTNCheck->pState.stage++;
return RC_NONE;
case 2:
/* Settle */
Si3226x_polled_delay(&(pPSTNCheck->pState), PSTN_DET_OPEN_FEMF_SETTLE);
return RC_NONE;
case 3:
/* Measure HAZV */
pPSTNCheck->vdiff_open = Si3226x_ReadMADCScaled(pProslic,VDIFF_COARSE,0);
/* Stop PSTN check if differential voltage > max_femf_vopen present */
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
{
LOGPRINT("Si3226x Diff PSTN : Vopen = %d mV\n", pPSTNCheck->vdiff_open);
}
#endif
if(abs_int32(pPSTNCheck->vdiff_open) > pPSTNCheck->max_femf_vopen)
{
pPSTNCheck->pState.stage = 70;
pPSTNCheck->return_status = RC_PSTN_OPEN_FEMF;
}
else
{
pPSTNCheck->pState.stage = 10;
}
return 0;
case 10:
/* Load first DC feed preset */
ProSLIC_DCFeedSetup(pProslic,pPSTNCheck->dcfPreset1);
ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);
pPSTNCheck->pState.stage++;
return RC_NONE;
case 11:
/* Settle */
Si3226x_polled_delay(&(pPSTNCheck->pState), PSTN_DET_DIFF_IV1_SETTLE);
return RC_NONE;
case 12:
/* Measure VDIFF and ILOOP, switch to 2nd DCFEED setup */
pPSTNCheck->vdiff1[pPSTNCheck->pState.sampleIterations] = Si3226x_ReadMADCScaled(pProslic,VDIFF_FILT,0);
pPSTNCheck->iloop1[pPSTNCheck->pState.sampleIterations] = Si3226x_ReadMADCScaled(pProslic,MADC_ILOOP,0);
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
{
LOGPRINT("Si3226x Diff PSTN : Vdiff1[%d] = %d mV\n", pPSTNCheck->pState.sampleIterations,pPSTNCheck->vdiff1[pPSTNCheck->pState.sampleIterations]);
LOGPRINT("Si3226x Diff PSTN : Iloop1[%d] = %d uA\n", pPSTNCheck->pState.sampleIterations,pPSTNCheck->iloop1[pPSTNCheck->pState.sampleIterations]);
}
#endif
pPSTNCheck->pState.sampleIterations++;
if(pPSTNCheck->pState.sampleIterations >= pPSTNCheck->samples)
{
ProSLIC_DCFeedSetup(pProslic,pPSTNCheck->dcfPreset2);
pPSTNCheck->pState.stage++;
pPSTNCheck->pState.sampleIterations = 0;
}
return RC_NONE;
case 13:
/* Settle feed 500ms */
Si3226x_polled_delay(&(pPSTNCheck->pState), PSTN_DET_DIFF_IV2_SETTLE);
return RC_NONE;
case 14:
/* Measure VDIFF and ILOOP*/
pPSTNCheck->vdiff2[pPSTNCheck->pState.sampleIterations] = Si3226x_ReadMADCScaled(pProslic,VDIFF_FILT,0);
pPSTNCheck->iloop2[pPSTNCheck->pState.sampleIterations] = Si3226x_ReadMADCScaled(pProslic,MADC_ILOOP,0);
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
{
LOGPRINT("Si3226x Diff PSTN : Vdiff2[%d] = %d mV\n", pPSTNCheck->pState.sampleIterations,pPSTNCheck->vdiff2[pPSTNCheck->pState.sampleIterations]);
LOGPRINT("Si3226x Diff PSTN : Iloop2[%d] = %d uA\n", pPSTNCheck->pState.sampleIterations,pPSTNCheck->iloop2[pPSTNCheck->pState.sampleIterations]);
}
#endif
pPSTNCheck->pState.sampleIterations++;
if(pPSTNCheck->pState.sampleIterations >= pPSTNCheck->samples)
{
/* Compute averages */
for (i=0; i<pPSTNCheck->samples; i++)
{
pPSTNCheck->vdiff1_avg += pPSTNCheck->vdiff1[i];
pPSTNCheck->iloop1_avg += pPSTNCheck->iloop1[i];
pPSTNCheck->vdiff2_avg += pPSTNCheck->vdiff2[i];
pPSTNCheck->iloop2_avg += pPSTNCheck->iloop2[i];
}
pPSTNCheck->vdiff1_avg /= pPSTNCheck->samples;
pPSTNCheck->iloop1_avg /= pPSTNCheck->samples;
pPSTNCheck->vdiff2_avg /= pPSTNCheck->samples;
pPSTNCheck->iloop2_avg /= pPSTNCheck->samples;
/* Force small (probably offset) currents to minimum value */
if(abs_int32(pPSTNCheck->iloop1_avg) < PSTN_DET_MIN_ILOOP) pPSTNCheck->iloop1_avg = PSTN_DET_MIN_ILOOP;
if(abs_int32(pPSTNCheck->iloop2_avg) < PSTN_DET_MIN_ILOOP) pPSTNCheck->iloop2_avg = PSTN_DET_MIN_ILOOP;
/* Calculate measured loop impedance */
pPSTNCheck->rl1 = abs_int32((pPSTNCheck->vdiff1_avg*1000L)/pPSTNCheck->iloop1_avg);
pPSTNCheck->rl2 = abs_int32((pPSTNCheck->vdiff2_avg*1000L)/pPSTNCheck->iloop2_avg);
/* Force non-zero loop resistance */
if(pPSTNCheck->rl1 == 0) pPSTNCheck->rl1 = 1;
if(pPSTNCheck->rl2 == 0) pPSTNCheck->rl2 = 1;
/* Qualify loop impedances */
pPSTNCheck->rl_ratio = (pPSTNCheck->rl1*1000L)/pPSTNCheck->rl2;
#ifdef ENABLE_DEBUG
if (pProslic->debugMode)
{
LOGPRINT("Si3226x DiffPSTN : VDIFF1 = %d mV\n",pPSTNCheck->vdiff1_avg);
LOGPRINT("Si3226x DiffPSTN : ILOOP1 = %d uA\n",pPSTNCheck->iloop1_avg);
LOGPRINT("Si3226x DiffPSTN : VDIFF2 = %d mV\n",pPSTNCheck->vdiff2_avg);
LOGPRINT("Si3226x DiffPSTN : ILOOP2 = %d uA\n",pPSTNCheck->iloop2_avg);
LOGPRINT("Si3226x DiffPSTN : RL1 = %d ohm\n",pPSTNCheck->rl1);
LOGPRINT("Si3226x DiffPSTN : RL2 = %d ohm\n",pPSTNCheck->rl2);
LOGPRINT("Si3226x DiffPSTN : RL_Ratio = %d \n",pPSTNCheck->rl_ratio);
}
#endif
/* Restore */
pPSTNCheck->pState.sampleIterations = 0;
pPSTNCheck->pState.stage = 70;
}
return RC_NONE;
case 70: /* Reset test state, restore entry conditions */
ProSLIC_DCFeedSetup(pProslic,pPSTNCheck->entryDCFeedPreset);
ProSLIC_SetLinefeedStatus(pProslic,pPSTNCheck->lfstate_entry);
if(pProslic->deviceId->chipRev != 0) {
WriteReg(pProHW,pProslic->channel,ENHANCE, pPSTNCheck->enhanceRegSave);
}
pPSTNCheck->pState.stage = 0;
pPSTNCheck->pState.waitIterations = 0;
pPSTNCheck->pState.sampleIterations = 0;
return pPSTNCheck->return_status;
}
return RC_NONE;
}
#endif
/*
** Function: Si3226x_ReadReg
**
** Description:
** Allows direct SPI access at ProSLIC layer
** Channel embeded in channel obj, so it is not passed into this func
**
** Returns:
** uInt8 - register contents
*/
uInt8 Si3226x_ReadReg (proslicChanType *pProslic, uInt8 addr)
{
return (ReadReg(pProHW,pProslic->channel, addr));
}
/*
** Function: Si3226x_WriteReg
**
** Description:
** Allows direct SPI access at ProSLIC layer
** Channel embeded in channel obj, so it is not passed into this func
**
** Returns:
** RC_NONE
*/
int Si3226x_WriteReg (proslicChanType *pProslic, uInt8 addr, uInt8 data)
{
WriteReg(pProHW,pProslic->channel,addr,data);
return RC_NONE;
}
/*
** Function: Si3226x_ReadRAM
**
** Description:
** Allows direct SPI access at ProSLIC layer
** Channel embeded in channel obj, so it is not passed into this func
**
** Returns:
** uInt32 - RAM contents
*/
ramData Si3226x_ReadRAM (proslicChanType *pProslic, uInt16 addr)
{
return (ReadRAM(pProHW,pProslic->channel, addr));
}
/*
** Function: Si3226x_WriteRAM
**
** Description:
** Allows direct SPI access at ProSLIC layer
** Channel embeded in channel obj, so it is not passed into this func
**
** Returns:
** RC_NONE
*/
int Si3226x_WriteRAM (proslicChanType *pProslic, uInt16 addr, ramData data)
{
WriteRAM(pProHW,pProslic->channel,addr,data);
return RC_NONE;
}