[][Add Proslic SI3218x audio codec driver]
[Description]
Add Proslic SI3218x audio codec driver
[Release-log]
N/A
Change-Id: I30edf714fda413b220b6a0f3e301a7bc3f899c08
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5396999
diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si3218x_intf.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si3218x_intf.c
new file mode 100644
index 0000000..7b778f5
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si3218x_intf.c
@@ -0,0 +1,3135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SI3218X ProSLIC interface implementation file
+ *
+ * Author(s):
+ * cdp
+ *
+ * Distributed by:
+ * Silicon Laboratories, Inc
+ *
+ * This file contains proprietary information.
+ * No dissemination allowed without prior written permission from
+ * Silicon Laboratories, Inc.
+ *
+ */
+
+#include "../config_inc/si_voice_datatypes.h"
+#include "../inc/si_voice_ctrl.h"
+#include "../inc/si_voice_timer_intf.h"
+#include "../inc/proslic.h"
+#include "../inc/si3218x.h"
+#include "../inc/si3218x_intf.h"
+#include "../inc/si3218x_registers.h"
+#include "../config_inc/proslic_api_config.h"
+
+#define SI3218X_IRING_LIM_MAX 0xA00000L /* 103mA */
+#define SI3218X_REVA 2
+
+#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 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 ReadRAMX deviceId->ctrlInterface->ReadRAM_fptr
+#define WriteRAMX deviceId->ctrlInterface->WriteRAM_fptr
+
+#define DEVICE_KEY_MIN 0x6E
+#define DEVICE_KEY_MAX 0x77
+
+#ifdef ENABLE_DEBUG
+static const char LOGPRINT_PREFIX[] = "Si3218x: ";
+#endif
+
+/*
+** Externs
+*/
+
+/* General Configuration */
+extern Si3218x_General_Cfg Si3218x_General_Configuration;
+#ifdef SIVOICE_MULTI_BOM_SUPPORT
+extern const proslicPatch SI3218X_PATCH_A;
+extern Si3218x_General_Cfg Si3218x_General_Configuration_MultiBOM[];
+extern int si3218x_genconf_multi_max_preset;
+#else
+extern const proslicPatch SI3218X_PATCH_A_DEFAULT;
+#endif
+
+/* Ringing */
+#ifndef DISABLE_RING_SETUP
+extern Si3218x_Ring_Cfg Si3218x_Ring_Presets[];
+#endif
+
+/* Zsynth */
+#ifndef DISABLE_ZSYNTH_SETUP
+extern Si3218x_Impedance_Cfg Si3218x_Impedance_Presets [];
+#endif
+
+/* Audio Gain Scratch */
+extern Si3218x_audioGain_Cfg Si3218x_audioGain_Presets[];
+
+/* Pulse Metering */
+#ifndef DISABLE_PULSE_SETUP
+extern Si3218x_PulseMeter_Cfg Si3218x_PulseMeter_Presets [];
+#endif
+
+/* PCM */
+#ifndef DISABLE_PCM_SETUP
+extern Si3218x_PCM_Cfg Si3218x_PCM_Presets [];
+#endif
+
+#define SI3218X_RAM_DCDC_DCFF_ENABLE SI3218X_RAM_GENERIC_8
+#define GCONF Si3218x_General_Configuration
+
+/*
+** Constants
+*/
+#define BIT20LSB 1048576L
+#define OITHRESH_OFFS 900L
+#define OITHRESH_SCALE 100L
+#define OVTHRESH_OFFS 71000
+#define OVTHRESH_SCALE 3000L
+#define UVTHRESH_OFFS 4057L
+#define UVTHRESH_SCALE 187L
+#define UVHYST_OFFS 548L
+#define UVHYST_SCALE 47L
+
+/*
+** 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 data)
+{
+ /* For the parts that have a HV variant, we map to the lower voltage version,
+ the actual differences are handled in the constants file
+ */
+
+ const uInt8 partNums[8] =
+ {
+ UNSUPPORTED_PART_NUM, UNSUPPORTED_PART_NUM, UNSUPPORTED_PART_NUM, UNSUPPORTED_PART_NUM,
+ SI32184, SI32182, SI32185, SI32183
+ };
+
+ uInt8 partNum = (data & 0x38) >> 3; /* PART_NUM[2:0] = ID[5:3] */
+
+ return partNums[ partNum ];
+}
+
+int Si3218x_GetChipInfo(proslicChanType_ptr pProslic)
+{
+ uInt8 id;
+ id = ReadReg(pProHW, pProslic->channel, PROSLIC_REG_ID);
+
+ pProslic->deviceId->chipRev = id & 0x7;
+ pProslic->deviceId->chipType = getChipType(id);
+
+ if(pProslic->deviceId->chipType == UNSUPPORTED_PART_NUM)
+ {
+#ifdef ENABLE_DEBUG
+ LOGPRINT("%sregister 0 read = 0x%02X\n", LOGPRINT_PREFIX, id);
+#endif
+ return RC_SPI_FAIL;
+ }
+ else
+ {
+ return RC_NONE;
+ }
+}
+
+/*
+** Function: Si3218x_ConverterSetup
+**
+** Description:
+** Program revision specific settings before powering converter
+**
+** Specifically, from general parameters and knowledge that this
+** is Si32188x, setup dcff drive, gate drive polarity, and charge pump.
+**
+** Returns:
+** int (error)
+**
+*/
+int Si3218x_ConverterSetup(proslicChanType_ptr pProslic)
+{
+ ramData inv_off;
+
+ /* Option to add a per-channel inversion for maximum flexibility */
+ if(pProslic->dcdc_polarity_invert)
+ {
+ inv_off = 0x100000L;
+ }
+ else
+ {
+ inv_off = 0x0L;
+ }
+
+ switch(Si3218x_General_Configuration.bom_option)
+ {
+ case BO_DCDC_LCQC_5W:
+ case BO_DCDC_LCCB:
+ case BO_DCDC_LCCB110:
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_LIFT_EN,
+ 0x0L); /* dcff disabled */
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_SWDRV_POL,
+ inv_off); /* non-inverted */
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_CPUMP,
+ 0x100000L); /* Charge pump on */
+ Delay(pProTimer,20); /* Cpump settle */
+ break;
+
+ case BO_DCDC_BUCK_BOOST:
+ /*
+ ** RevC buck-boost designs are identical to RevB - no gate drive,
+ ** dcff enabled, non-inverting (charge pump off)
+ */
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_CPUMP,0x0L);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_SWDRV_POL,inv_off);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_LIFT_EN,
+ 0x100000L); /* dcff enabled */
+ break;
+
+ default:
+ return RC_DCDC_SETUP_ERR;
+ }
+
+ return RC_NONE;
+}
+
+/*
+** Function: Si3218x_PowerUpConverter
+**
+** Description:
+** Powers all DC/DC converters sequentially with delay to minimize
+** peak power draw on VDC.
+**
+** Returns:
+** int (error)
+**
+*/
+
+int Si3218x_PowerUpConverter(proslicChanType_ptr pProslic)
+{
+ errorCodeType error = RC_DCDC_SETUP_ERR;
+ int32 vbath,vbat;
+ uInt8 reg = 0;
+ int timer = 0;
+
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ /*
+ ** - 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
+ */
+
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED,
+ LF_FWD_OHT); /* Force out of pwrsave mode if called in error */
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED,
+ LF_OPEN); /* Ensure open line before powering up converter */
+ reg = ReadReg(pProHW,pProslic->channel,SI3218X_REG_ENHANCE);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_ENHANCE,
+ reg&0x07); /* Disable powersave mode */
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_DCDC,
+ 0x700000L); /* In case OV or UV previously occurred */
+
+ /*
+ ** Setup converter drive polarity and charge pump enable
+ ** based on bom
+ */
+
+ error = Si3218x_ConverterSetup(pProslic);
+
+ if(error != RC_NONE)
+ {
+ DEBUG_PRINT (pProslic, "%sChannel %d : DCDC initialization failed\n",
+ LOGPRINT_PREFIX, pProslic->channel);
+ return error;
+ }
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_DCDC,0x600000L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_BIAS,0x200000L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_HVIC,0x200000L);
+ Delay(pProTimer,50);
+
+ vbath = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_VBATH_EXPECT);
+ vbat = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_VBAT);
+ if(vbat & 0x10000000L)
+ {
+ vbat |= 0xF0000000L;
+ }
+ if(vbat < (vbath / 2))
+ {
+ pProslic->channelEnable = 0;
+ error = RC_VBAT_UP_TIMEOUT;
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_DCDC,
+ 0x300000L); /* shutdown converter */
+ DEBUG_PRINT (pProslic,
+ "%sChannel %d : DCDC Short Circuit Failure - disabling channel\n%sVBAT = %d.%d\n",
+ LOGPRINT_PREFIX, pProslic->channel, LOGPRINT_PREFIX,
+ (int)((vbat/SCALE_V_MADC)/1000),
+ SIVOICE_ABS(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
+ return error;
+ }
+ else /* Enable analog converter */
+ {
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_DCDC_STATUS,0L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_DCDC,0x400000L);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_ENHANCE,
+ reg); /* Restore ENHANCE */
+ Delay(pProTimer,50);
+ }
+
+ /*
+ ** - monitor vbat vs expected level (VBATH_EXPECT)
+ */
+ vbath = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_VBATH_EXPECT);
+ do
+ {
+ vbat = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_VBAT);
+ if(vbat & 0x10000000L)
+ {
+ vbat |= 0xF0000000L;
+ }
+ Delay(pProTimer,10);
+ }
+ while((vbat < (vbath - COMP_5V))
+ &&(timer++ < SI3218X_TIMEOUT_DCDC_UP)); /* 2 sec timeout */
+
+ DEBUG_PRINT (pProslic, "%sChannel %d : VBAT Up = %d.%d v\n",
+ LOGPRINT_PREFIX,
+ pProslic->channel,(int)((vbat/SCALE_V_MADC)/1000),
+ SIVOICE_ABS(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
+ if(timer > SI3218X_TIMEOUT_DCDC_UP)
+ {
+ /* Error handling - shutdown converter, disable channel, set error tag */
+ pProslic->channelEnable = 0;
+ error = RC_VBAT_UP_TIMEOUT;
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_DCDC,
+ 0x900000L); /* shutdown converter */
+ DEBUG_PRINT (pProslic, "%sChannel %d : DCDC Power up timeout : Status=0x%08X\n",
+ LOGPRINT_PREFIX, pProslic->channel, ReadRAM(pProHW,pProslic->channel,
+ SI3218X_RAM_DCDC_STATUS));
+ }
+
+ return error;
+}
+
+/*
+**
+** PROSLIC INITIALIZATION FUNCTIONS
+**
+*/
+
+/*
+** Function: Si3218x_Init_MultiBOM
+**
+** Description:
+** - probe SPI to establish daisy chain length
+** - load patch
+** - initialize general parameters
+** - calibrate madc
+** - bring up DC/DC converters
+** - calibrate everything except madc & lb
+**
+** Input Parameters:
+** pProslic: pointer to PROSLIC object array
+** fault: error code
+**
+** Return:
+** error code
+*/
+
+#ifdef SIVOICE_MULTI_BOM_SUPPORT
+int Si3218x_Init_MultiBOM (proslicChanType_ptr *pProslic, int size, int preset)
+{
+
+ if(preset < si3218x_genconf_multi_max_preset)
+ {
+ /* Copy selected General Configuration parameters to Std structure */
+ Si3218x_General_Configuration = Si3218x_General_Configuration_MultiBOM[preset];
+ }
+ else
+ {
+ return RC_INVALID_PRESET;
+ }
+ return Si3218x_Init_with_Options(pProslic,size, INIT_NO_OPT);
+}
+#endif
+
+
+/*
+** Function: Si3218x_SelectPatch
+**
+** Select patch based on general parameters
+**
+** Input Parameters:
+** pProslic: pointer to PROSLIC object array
+** fault: error code
+** patch: Pointer to proslicPatch pointer
+**
+** Return:
+** error code
+*/
+int Si3218x_SelectPatch(proslicChanType_ptr pProslic,
+ const proslicPatch **patch)
+{
+
+#ifdef SIVOICE_MULTI_BOM_SUPPORT
+ if(Si3218x_General_Configuration.bom_option == BO_DCDC_LCQC_5W
+ || Si3218x_General_Configuration.bom_option == BO_DCDC_LCCB
+ || Si3218x_General_Configuration.bom_option == BO_DCDC_LCCB110
+ || Si3218x_General_Configuration.bom_option == BO_DCDC_BUCK_BOOST)
+ {
+ *patch = &(SI3218X_PATCH_A);
+ }
+ else
+ {
+ DEBUG_PRINT(pProslic, "%sChannel %d : Invalid Patch\n", LOGPRINT_PREFIX,
+ pProslic->channel);
+ pProslic->channelEnable = 0;
+ pProslic->error = RC_INVALID_PATCH;
+ return RC_INVALID_PATCH;
+ }
+#else
+ SILABS_UNREFERENCED_PARAMETER(pProslic);
+ *patch = &(SI3218X_PATCH_A_DEFAULT);
+#endif
+
+ return RC_NONE;
+}
+
+/*
+** Function: Si3218x_GenParamUpdate
+**
+** Update general parameters
+**
+** Input Parameters:
+** pProslic: pointer to PROSLIC object array
+** fault: error code
+**
+** Return:
+** error code
+*/
+
+int Si3218x_GenParamUpdate(proslicChanType_ptr pProslic,initSeqType seq)
+{
+ ramData ram_data;
+ uInt8 data;
+
+ switch(seq)
+ {
+ case INIT_SEQ_PRE_CAL:
+ /*
+ ** Force pwrsave off and disable AUTO-tracking - set to user configured state after cal
+ */
+ WriteReg(pProHW, pProslic->channel,SI3218X_REG_ENHANCE,0);
+ WriteReg(pProHW, pProslic->channel,SI3218X_REG_AUTO,0x2F);
+
+ /*
+ ** General Parameter Updates
+ */
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_P_TH_HVIC,
+ Si3218x_General_Configuration.p_th_hvic);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_COEF_P_HVIC,
+ Si3218x_General_Configuration.coef_p_hvic);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_BAT_HYST,
+ Si3218x_General_Configuration.bat_hyst);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VBATH_EXPECT,
+ Si3218x_General_Configuration.vbath_expect);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VBATR_EXPECT,
+ Si3218x_General_Configuration.vbatr_expect);
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_PWRSAVE_TIMER,
+ Si3218x_General_Configuration.pwrsave_timer);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_OFFHOOK_THRESH,
+ Si3218x_General_Configuration.pwrsave_ofhk_thresh);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VBAT_TRACK_MIN,
+ Si3218x_General_Configuration.vbat_track_min);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VBAT_TRACK_MIN_RNG,
+ Si3218x_General_Configuration.vbat_track_min_rng);
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_THERM_DBI,
+ Si3218x_General_Configuration.therm_dbi);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VOV_DCDC_SLOPE,
+ Si3218x_General_Configuration.vov_dcdc_slope);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VOV_DCDC_OS,
+ Si3218x_General_Configuration.vov_dcdc_os);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VOV_RING_BAT_MAX,
+ Si3218x_General_Configuration.vov_ring_bat_max);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_VERR,
+ Si3218x_General_Configuration.dcdc_verr);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_VERR_HYST,
+ Si3218x_General_Configuration.dcdc_verr_hyst);
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_PD_UVLO,
+ Si3218x_General_Configuration.pd_uvlo);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_PD_OVLO,
+ Si3218x_General_Configuration.pd_ovlo);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_PD_OCLO,
+ Si3218x_General_Configuration.pd_oclo);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_PD_SWDRV,
+ Si3218x_General_Configuration.pd_swdrv);
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_UVPOL,
+ Si3218x_General_Configuration.dcdc_uvpol);
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_RNGTYPE,
+ Si3218x_General_Configuration.dcdc_rngtype);
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_ANA_TOFF,
+ Si3218x_General_Configuration.dcdc_ana_toff);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_ANA_TONMIN,
+ Si3218x_General_Configuration.dcdc_ana_tonmin);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_ANA_TONMAX,
+ Si3218x_General_Configuration.dcdc_ana_tonmax);
+
+
+ /*
+ ** Hardcoded RAM
+ */
+
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_OITHRESH_LO,
+ GCONF.i_oithresh_lo);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_OITHRESH_HI,
+ GCONF.i_oithresh_hi);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_OVTHRESH,GCONF.v_ovthresh);
+
+ ram_data = (GCONF.v_uvthresh > UVTHRESH_OFFS)?(GCONF.v_uvthresh -
+ UVTHRESH_OFFS)/UVTHRESH_SCALE:0L;
+ ram_data *= BIT20LSB;
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_UVTHRESH,ram_data);
+
+ ram_data = (GCONF.v_uvhyst > UVHYST_OFFS)?(GCONF.v_uvhyst -
+ UVHYST_OFFS)/UVHYST_SCALE:0L;
+ ram_data *= BIT20LSB;
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_UVHYST,ram_data);
+
+ /* Set default audio gain based on PM bom */
+ if(Si3218x_General_Configuration.pm_bom == BO_PM_BOM)
+ {
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_SCALE_KAUDIO,BOM_KAUDIO_PM);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_AC_ADC_GAIN,BOM_AC_ADC_GAIN_PM);
+ }
+ else
+ {
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_SCALE_KAUDIO,BOM_KAUDIO_NO_PM);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_AC_ADC_GAIN,
+ BOM_AC_ADC_GAIN_NO_PM);
+ }
+
+ /*
+ ** Hardcoded changes to default settings
+ */
+ data = ReadReg(pProHW, pProslic->channel,SI3218X_REG_GPIO_CFG1);
+ data &= 0xF9; /* Clear DIR for GPIO 1&2 */
+ data |= 0x60; /* Set ANA mode for GPIO 1&2 */
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_GPIO_CFG1,
+ data); /* coarse sensors analog mode */
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_PDN,
+ 0x80); /* madc powered in open state */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_A1_1,
+ 0x71EB851L); /* Fix HPF corner */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PD_REF_OSC,
+ 0x200000L); /* PLL freerun workaround */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ILOOPLPF,
+ 0x4EDDB9L); /* 20pps pulse dialing enhancement */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ILONGLPF,
+ 0x806D6L); /* 20pps pulse dialing enhancement */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VDIFFLPF,
+ 0x10038DL); /* 20pps pulse dialing enhancement */
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_DCDC_VREF_CTRL,0x0L);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VCM_TH,0x106240L);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VCMLPF,0x10059FL);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_CM_SPEEDUP_TIMER,0x0F0000);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_VCM_HYST,0x206280L);
+
+ /* Prevent Ref Osc from powering down in PLL Freerun mode (pd_ref_osc) */
+ ram_data = ReadRAM(pProHW, pProslic->channel,SI3218X_RAM_PWRSAVE_CTRL_LO);
+ WriteRAM(pProHW, pProslic->channel,SI3218X_RAM_PWRSAVE_CTRL_LO,
+ ram_data&0x07FFFFFFL); /* clear b27 */
+ break;
+
+
+ case INIT_SEQ_POST_CAL:
+ WriteReg(pProHW, pProslic->channel,SI3218X_REG_ENHANCE,
+ Si3218x_General_Configuration.enhance&0x1F);
+ WriteReg(pProHW, pProslic->channel,SI3218X_REG_AUTO,
+ Si3218x_General_Configuration.auto_reg);
+ if(Si3218x_General_Configuration.zcal_en)
+ {
+ WriteReg(pProHW,pProslic->channel, SI3218X_REG_ZCAL_EN, 0x04);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return RC_NONE;
+}
+
+/*
+** Function: Si3218x_Init_with_Options
+**
+** Description:
+** - probe SPI to establish daisy chain length
+** - load patch
+** - initialize general parameters
+** - calibrate madc
+** - bring up DC/DC converters
+** - calibrate everything except madc & lb
+**
+** Input Parameters:
+** pProslic: pointer to PROSLIC object array
+** fault: error code
+**
+** Return:
+** error code
+*/
+
+int Si3218x_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;
+ uInt8 calSetup[] = {0x00, 0x00, 0x01, 0x80}; /* CALR0-CALR3 */
+ int k, device_count;
+ const proslicPatch *patch;
+ uInt8 status;
+
+ LOGPRINT("%s(%d) size = %d init_opt = %d\n", __FUNCTION__, __LINE__, size,
+ init_opt);
+ /*
+ **
+ ** 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 = Si3218x_General_Configuration.device_key;
+
+ if((data < DEVICE_KEY_MIN)||(data > DEVICE_KEY_MAX))
+ {
+ pProslic[0]->error = RC_INVALID_GEN_PARAM;
+ return pProslic[0]->error;
+ }
+
+ /* reset error code */
+ for(k = 0; k < size; k++)
+ {
+ pProslic[k]->error = RC_NONE;
+ }
+
+ if( (init_opt == INIT_REINIT) || (init_opt == INIT_SOFTRESET) )
+ {
+ ProSLIC_ReInit_helper(pProslic, size, init_opt, SI3218X_CHAN_PER_DEVICE);
+
+ /* for single channel devices, we need do a full restore.. */
+ if(init_opt == INIT_REINIT)
+ {
+ init_opt = 0;
+ }
+}
+
+ if( init_opt != INIT_REINIT )
+ {
+ if( (SiVoice_IdentifyChannels(pProslic, size, &device_count, NULL) != RC_NONE)
+ ||(device_count == 0) )
+ {
+ DEBUG_PRINT(*pProslic, "%s: failed to detect any ProSLICs\n", LOGPRINT_PREFIX);
+ return RC_SPI_FAIL;
+ }
+
+ /*
+ ** Probe each channel and enable all channels that respond
+ */
+ for (k=0; k<size; k++)
+ {
+ if ((pProslic[k]->channelEnable)
+ &&(pProslic[k]->channelType == PROSLIC))
+ {
+ if ( (ProSLIC_VerifyMasterStat(pProslic[k]) != RC_NONE)
+ || (ProSLIC_VerifyControlInterface(pProslic[k]) != RC_NONE) )
+ {
+ pProslic[k]->channelEnable = 0;
+ pProslic[k]->error = RC_SPI_FAIL;
+ DEBUG_PRINT(*pProslic, "%s: SPI communications or PCLK/FS failure\n", LOGPRINT_PREFIX);
+ return pProslic[k]->error; /* Halt init if SPI fail */
+ }
+ }
+ }
+ } /* init_opt !REINIT */
+
+
+ if( (init_opt != INIT_NO_PATCH_LOAD ) && (init_opt != INIT_REINIT) )
+ {
+ /*
+ ** Load patch (load on every channel since single channel device)
+ */
+ for (k=0; k<size; k++)
+ {
+ if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC))
+ {
+
+ /* Select Patch*/
+ if (pProslic[k]->deviceId->chipRev == SI3218X_REVA )
+ {
+ status = (uInt8) Si3218x_SelectPatch(pProslic[k],&patch);
+ }
+ else
+ {
+ DEBUG_PRINT(pProslic[k], "%sChannel %d : Unsupported Device Revision (%d)\n",
+ LOGPRINT_PREFIX, pProslic[k]->channel,pProslic[k]->deviceId->chipRev );
+ pProslic[k]->channelEnable = 0;
+ pProslic[k]->error = RC_UNSUPPORTED_DEVICE_REV;
+ return RC_UNSUPPORTED_DEVICE_REV;
+ }
+
+ data = 1; /* Use this as a flag to see if we need to load the patch */
+ /* If the patch doesn't match, we need to do a full init, change settings */
+ if(init_opt == INIT_SOFTRESET)
+ {
+ ramData patchData;
+ patchData = pProslic[k]->ReadRAMX(pProslic[k]->pProHWX, pProslic[k]->channel,
+ PROSLIC_RAM_PATCHID);
+
+ if( patchData == patch->patchSerial)
+ {
+ data = 0;
+ }
+ else
+ {
+ init_opt = INIT_NO_OPT;
+ }
+ } /* SOFTRESET */
+
+ /* Load Patch */
+ if(status == RC_NONE)
+ {
+ if(data == 1)
+ {
+ Si3218x_LoadPatch(pProslic[k],patch);
+#ifndef DISABLE_VERIFY_PATCH
+ /* Optional Patch Verification */
+ data = (uInt8)Si3218x_VerifyPatch(pProslic[k],patch);
+ if (data != RC_NONE)
+ {
+ DEBUG_PRINT(pProslic[k], "%sChannel %d : Patch verification failed (%d)\n",
+ LOGPRINT_PREFIX, k, data);
+ pProslic[k]->channelEnable=0;
+ pProslic[k]->error = RC_PATCH_ERR;
+ return data;
+ }
+#endif
+ }
+ }
+ else
+ {
+ return status;
+ }
+ } /* channel == PROSLIC */
+ } /* for all channles */
+ }/* init_opt - need to reload patch */
+
+ /*
+ ** Load general parameters - includes all BOM dependencies
+ */
+ if(init_opt != INIT_SOFTRESET)
+ {
+ for (k=0; k<size; k++)
+ {
+ if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC))
+ {
+ Si3218x_GenParamUpdate(pProslic[k],INIT_SEQ_PRE_CAL);
+ }
+
+ pProslic[k]->WriteRAMX(pProslic[k]->pProHWX,pProslic[k]->channel,
+ SI3218X_RAM_IRING_LIM,SI3218X_IRING_LIM_MAX);
+ }
+ }
+
+ if((init_opt != INIT_NO_CAL)
+ && (init_opt != INIT_SOFTRESET)) /* Must recal on single channel devices */
+ {
+ /*
+ ** Calibrate (madc offset)
+ */
+ ProSLIC_Calibrate(pProslic,size,calSetup,TIMEOUT_MADC_CAL);
+ }/* init_opt */
+
+ /*
+ ** 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))
+ {
+ pProslic[k]->error = Si3218x_PowerUpConverter(pProslic[k]);
+ }
+ }
+
+ if((init_opt != INIT_NO_CAL) && (init_opt != INIT_SOFTRESET))
+ {
+ /*
+ ** Calibrate remaining cals (except madc, lb)
+ */
+ calSetup[1] = SI3218X_CAL_STD_CALR1;
+ calSetup[2] = SI3218X_CAL_STD_CALR2;
+
+ ProSLIC_Calibrate(pProslic,size,calSetup,TIMEOUT_GEN_CAL);
+ }
+
+ /*
+ ** Apply post calibration general parameters
+ */
+ if(init_opt != INIT_SOFTRESET)
+ {
+ for (k=0; k<size; k++)
+ {
+
+ if ((pProslic[k]->channelEnable)&&(pProslic[k]->channelType == PROSLIC))
+ {
+ Si3218x_GenParamUpdate(pProslic[k],INIT_SEQ_POST_CAL);
+ }
+ }
+ }
+
+ /* Restore linefeed state after initialization for REINIT/SOFTRESET */
+ if( (init_opt == INIT_REINIT) || (init_opt == INIT_SOFTRESET) )
+ {
+ for(k = 0; k < size; k++)
+ {
+ pProslic[k]->WriteRegX(pProslic[k]->pProHWX,pProslic[k]->channel,
+ SI3218X_REG_LINEFEED,pProslic[k]->scratch);
+ }
+ }
+
+ /*
+ ** If any channel incurred a non-fatal error, return
+ ** RC_NON_FATAL_INIT_ERR to trigger user to read each channel's
+ ** error status
+ */
+ for (k=0; k<size; k++)
+ {
+ if(pProslic[k]->error != RC_NONE)
+ {
+ return RC_NON_FATAL_INIT_ERR;
+ }
+ }
+
+ return RC_NONE;
+}
+
+/*
+** Function: Si3218x_EnableInterrupts
+**
+** Description:
+** Enables interrupts
+**
+** Input Parameters:
+** pProslic: pointer to PROSLIC channel obj
+**
+** Returns:
+** 0
+*/
+
+int Si3218x_EnableInterrupts (proslicChanType_ptr pProslic)
+{
+ uInt8 i;
+#ifdef GCI_MODE
+ uInt8 data;
+#endif
+ /* Clear pending interrupts first */
+ for(i = SI3218X_REG_IRQ1; i < SI3218X_REG_IRQ4; i++)
+ {
+#ifdef GCI_MODE
+ data = ReadReg(pProHW,pProslic->channel, i);
+ WriteReg(pProHW,pProslic->channel,i,data); /*clear interrupts (gci only)*/
+#else
+ (void)ReadReg(pProHW,pProslic->channel, i);
+#endif
+
+ }
+
+ WriteReg (pProHW,pProslic->channel,SI3218X_REG_IRQEN1,
+ Si3218x_General_Configuration.irqen1);
+ WriteReg (pProHW,pProslic->channel,SI3218X_REG_IRQEN2,
+ Si3218x_General_Configuration.irqen2);
+ WriteReg (pProHW,pProslic->channel,SI3218X_REG_IRQEN3,
+ Si3218x_General_Configuration.irqen3);
+ WriteReg (pProHW,pProslic->channel,SI3218X_REG_IRQEN4,
+ Si3218x_General_Configuration.irqen4);
+
+ return RC_NONE;
+}
+
+/*
+**
+** PROSLIC CONFIGURATION FUNCTIONS
+**
+*/
+
+/*
+** Function: Si3218x_RingSetup
+**
+** Description:
+** configure ringing
+**
+** Input Parameters:
+** pProslic: pointer to PROSLIC channel obj
+** preset: ring preset
+**
+** Returns:
+** 0
+*/
+
+#ifndef DISABLE_RING_SETUP
+int Si3218x_RingSetup (proslicChanType *pProslic, int preset)
+{
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RTPER,
+ Si3218x_Ring_Presets[preset].rtper);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RINGFR,
+ Si3218x_Ring_Presets[preset].freq);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RINGAMP,
+ Si3218x_Ring_Presets[preset].amp);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RINGPHAS,
+ Si3218x_Ring_Presets[preset].phas);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RINGOF,
+ Si3218x_Ring_Presets[preset].offset);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_SLOPE_RING,
+ Si3218x_Ring_Presets[preset].slope_ring);
+
+ if(Si3218x_Ring_Presets[preset].iring_lim > SI3218X_IRING_LIM_MAX)
+ {
+ Si3218x_Ring_Presets[preset].iring_lim = SI3218X_IRING_LIM_MAX;
+ }
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_IRING_LIM,
+ Si3218x_Ring_Presets[preset].iring_lim);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RTACTH,
+ Si3218x_Ring_Presets[preset].rtacth);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RTDCTH,
+ Si3218x_Ring_Presets[preset].rtdcth);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RTACDB,
+ Si3218x_Ring_Presets[preset].rtacdb);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RTDCDB,
+ Si3218x_Ring_Presets[preset].rtdcdb);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VOV_RING_BAT,
+ Si3218x_Ring_Presets[preset].vov_ring_bat);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VOV_RING_GND,
+ Si3218x_Ring_Presets[preset].vov_ring_gnd);
+
+#ifndef NOCLAMP_VBATR
+ /* Always limit VBATR_EXPECT to the general configuration maximum */
+ if(Si3218x_Ring_Presets[preset].vbatr_expect >
+ Si3218x_General_Configuration.vbatr_expect)
+ {
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VBATR_EXPECT,
+ Si3218x_General_Configuration.vbatr_expect);
+ DEBUG_PRINT(pProslic,
+ "%sRingSetup : VBATR_EXPECT : Clamped to Gen Conf Limit\n",LOGPRINT_PREFIX);
+ }
+ else
+ {
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VBATR_EXPECT,
+ Si3218x_Ring_Presets[preset].vbatr_expect);
+ }
+
+#else
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VBATR_EXPECT,
+ Si3218x_Ring_Presets[preset].vbatr_expect);
+#endif
+
+
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_RINGTALO,
+ Si3218x_Ring_Presets[preset].talo);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_RINGTAHI,
+ Si3218x_Ring_Presets[preset].tahi);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_RINGTILO,
+ Si3218x_Ring_Presets[preset].tilo);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_RINGTIHI,
+ Si3218x_Ring_Presets[preset].tihi);
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VBAT_TRACK_MIN_RNG,
+ Si3218x_Ring_Presets[preset].dcdc_vref_min_rng);
+
+ /*
+ ** LPR Handler
+ **
+ ** If USERSTAT == 0x01, adjust RINGCON and clear USERSTAT
+ */
+ if (Si3218x_Ring_Presets[preset].userstat == 0x01)
+ {
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_RINGCON,
+ (0x80|Si3218x_Ring_Presets[preset].ringcon) & ~(0x40));
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_USERSTAT,0x00);
+ }
+ else
+ {
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_RINGCON,
+ Si3218x_Ring_Presets[preset].ringcon);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_USERSTAT,
+ Si3218x_Ring_Presets[preset].userstat);
+ }
+
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VCM_RING,
+ Si3218x_Ring_Presets[preset].vcm_ring);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VCM_RING_FIXED,
+ Si3218x_Ring_Presets[preset].vcm_ring_fixed);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_DELTA_VCM,
+ Si3218x_Ring_Presets[preset].delta_vcm);
+
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_DCDC_RNGTYPE,
+ Si3218x_Ring_Presets[preset].dcdc_rngtype);
+
+
+ /*
+ ** If multi bom supported **AND** a buck boost converter
+ ** is being used, force dcdc_rngtype to be fixed.
+ */
+#ifdef SIVOICE_MULTI_BOM_SUPPORT
+#define DCDC_RNGTYPE_BKBT 0L
+ /* Automatically adjust DCDC_RNGTYPE */
+ if(Si3218x_General_Configuration.bom_option == BO_DCDC_BUCK_BOOST)
+ {
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_DCDC_RNGTYPE,DCDC_RNGTYPE_BKBT);
+ }
+#endif
+
+
+ return RC_NONE;
+}
+#endif
+
+/*
+** Function: PROSLIC_ZsynthSetup
+**
+** Description:
+** configure impedance synthesis
+*/
+
+#ifndef DISABLE_ZSYNTH_SETUP
+int Si3218x_ZsynthSetup (proslicChanType *pProslic, int preset)
+{
+ uInt8 lf;
+ uInt8 cal_en = 0;
+ uInt16 timer = 500;
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ lf = ReadReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED,0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C0,
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C1,
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C2,
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C3,
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c3);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C0,
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C1,
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C2,
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C3,
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c3);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C2,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C3,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c3);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C4,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c4);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C5,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c5);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C6,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c6);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C7,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c7);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C8,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c8);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECFIR_C9,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_c9);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECIIR_B0,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_b0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECIIR_B1,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_b1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECIIR_A1,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_a1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ECIIR_A2,
+ Si3218x_Impedance_Presets[preset].hybrid.ecfir_a2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ZSYNTH_A1,
+ Si3218x_Impedance_Presets[preset].zsynth.zsynth_a1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ZSYNTH_A2,
+ Si3218x_Impedance_Presets[preset].zsynth.zsynth_a2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ZSYNTH_B1,
+ Si3218x_Impedance_Presets[preset].zsynth.zsynth_b1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ZSYNTH_B0,
+ Si3218x_Impedance_Presets[preset].zsynth.zsynth_b0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_ZSYNTH_B2,
+ Si3218x_Impedance_Presets[preset].zsynth.zsynth_b2);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_RA,
+ Si3218x_Impedance_Presets[preset].zsynth.ra);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACGAIN,
+ Si3218x_Impedance_Presets[preset].txgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACGAIN_SAVE,
+ Si3218x_Impedance_Presets[preset].rxgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACGAIN,
+ Si3218x_Impedance_Presets[preset].rxgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_B0_1,
+ Si3218x_Impedance_Presets[preset].rxachpf_b0_1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_B1_1,
+ Si3218x_Impedance_Presets[preset].rxachpf_b1_1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_A1_1,
+ Si3218x_Impedance_Presets[preset].rxachpf_a1_1);
+
+ /*
+ ** Scale based on desired gain plan
+ */
+ Si3218x_dbgSetTXGain(pProslic,Si3218x_Impedance_Presets[preset].txgain_db,
+ preset,TXACGAIN_SEL);
+ Si3218x_dbgSetRXGain(pProslic,Si3218x_Impedance_Presets[preset].rxgain_db,
+ preset,RXACGAIN_SEL);
+ Si3218x_TXAudioGainSetup(pProslic,TXACGAIN_SEL);
+ Si3218x_RXAudioGainSetup(pProslic,RXACGAIN_SEL);
+
+ /*
+ ** Perform Zcal in case OHT used (eg. no offhook event to trigger auto Zcal)
+ */
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_CALR0,0x00);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_CALR1,0x40);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_CALR2,0x00);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_CALR3,0x80); /* start cal */
+
+ /* Wait for zcal to finish */
+ do
+ {
+ cal_en = ReadReg(pProHW,pProslic->channel,SI3218X_REG_CALR3);
+ Delay(pProTimer,1);
+ timer--;
+ }
+ while((cal_en&0x80)&&(timer>0));
+
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED,lf);
+
+ if(timer > 0)
+ {
+ return RC_NONE;
+ }
+ else
+ {
+ return RC_CAL_TIMEOUT;
+ }
+}
+#endif
+
+/*
+** Function: PROSLIC_AudioGainSetup
+**
+** Description:
+** configure audio gains
+*/
+int Si3218x_TXAudioGainSetup (proslicChanType *pProslic, int preset)
+{
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACGAIN,
+ Si3218x_audioGain_Presets[preset].acgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C0,
+ Si3218x_audioGain_Presets[preset].aceq_c0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C1,
+ Si3218x_audioGain_Presets[preset].aceq_c1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C2,
+ Si3218x_audioGain_Presets[preset].aceq_c2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C3,
+ Si3218x_audioGain_Presets[preset].aceq_c3);
+
+ return RC_NONE;
+}
+
+/*
+** Function: PROSLIC_AudioGainSetup
+**
+** Description:
+** configure audio gains
+*/
+
+int Si3218x_RXAudioGainSetup (proslicChanType *pProslic, int preset)
+{
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACGAIN_SAVE,
+ Si3218x_audioGain_Presets[preset].acgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACGAIN,
+ Si3218x_audioGain_Presets[preset].acgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C0,
+ Si3218x_audioGain_Presets[preset].aceq_c0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C1,
+ Si3218x_audioGain_Presets[preset].aceq_c1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C2,
+ Si3218x_audioGain_Presets[preset].aceq_c2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C3,
+ Si3218x_audioGain_Presets[preset].aceq_c3);
+
+ return RC_NONE;
+}
+
+
+/*
+** Function: PROSLIC_AudioGainScale
+**
+** Description:
+** Multiply path gain by passed value for PGA and EQ scale (no reference to dB,
+** multiply by a scale factor)
+*/
+int Si3218x_AudioGainScale (proslicChanType *pProslic, int preset,
+ uInt32 pga_scale, uInt32 eq_scale,int rx_tx_sel)
+{
+
+ if(rx_tx_sel == TXACGAIN_SEL)
+ {
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].acgain =
+ (Si3218x_Impedance_Presets[preset].txgain/1000)*pga_scale;
+ if (Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c0 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c0 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c1 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c1 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c2 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c2 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c3 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c3 |= 0xf0000000L;
+ }
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c0 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c0/1000)*eq_scale;
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c1 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c1/1000)*eq_scale;
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c2 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c2/1000)*eq_scale;
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c3 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.txaceq_c3/1000)*eq_scale;
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACGAIN,
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].acgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C0,
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C1,
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C2,
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACEQ_C3,
+ Si3218x_audioGain_Presets[TXACGAIN_SEL].aceq_c3);
+ }
+ else
+ {
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].acgain =
+ (Si3218x_Impedance_Presets[preset].rxgain/1000)*pga_scale;
+ if (Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c0 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c0 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c1 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c1 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c2 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c2 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c3 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c3 |= 0xf0000000L;
+ }
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c0 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c0/1000)*eq_scale;
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c1 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c1/1000)*eq_scale;
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c2 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c2/1000)*eq_scale;
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c3 = ((int32)
+ Si3218x_Impedance_Presets[preset].audioEQ.rxaceq_c3/1000)*eq_scale;
+
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACGAIN_SAVE,
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].acgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACGAIN,
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].acgain);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C0,
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C1,
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C2,
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACEQ_C3,
+ Si3218x_audioGain_Presets[RXACGAIN_SEL].aceq_c3);
+ }
+ return 0;
+}
+int Si3218x_TXAudioGainScale (proslicChanType *pProslic, int preset,
+ uInt32 pga_scale, uInt32 eq_scale)
+{
+ return Si3218x_AudioGainScale(pProslic,preset,pga_scale,eq_scale,TXACGAIN_SEL);
+}
+int Si3218x_RXAudioGainScale (proslicChanType *pProslic, int preset,
+ uInt32 pga_scale, uInt32 eq_scale)
+{
+ return Si3218x_AudioGainScale(pProslic,preset,pga_scale,eq_scale,RXACGAIN_SEL);
+}
+
+
+/*
+** Function: PROSLIC_DCFeedSetup
+**
+** Description:
+** configure dc feed
+*/
+
+#ifndef DISABLE_DCFEED_SETUP
+int Si3218x_DCFeedSetupCfg (proslicChanType *pProslic, Si3218x_DCfeed_Cfg *cfg,
+ int preset)
+{
+ uInt8 lf;
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+ lf = ReadReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED,0);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_SLOPE_VLIM,
+ cfg[preset].slope_vlim);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_SLOPE_RFEED,
+ cfg[preset].slope_rfeed);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_SLOPE_ILIM,
+ cfg[preset].slope_ilim);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_SLOPE_DELTA1,cfg[preset].delta1);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_SLOPE_DELTA2,cfg[preset].delta2);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_V_VLIM,cfg[preset].v_vlim);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_V_RFEED,cfg[preset].v_rfeed);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_V_ILIM,cfg[preset].v_ilim);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_CONST_RFEED,
+ cfg[preset].const_rfeed);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_CONST_ILIM,
+ cfg[preset].const_ilim);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_I_VLIM,cfg[preset].i_vlim);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LCRONHK,cfg[preset].lcronhk);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LCROFFHK,cfg[preset].lcroffhk);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LCRDBI,cfg[preset].lcrdbi);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LONGHITH,cfg[preset].longhith);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LONGLOTH,cfg[preset].longloth);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LONGDBI,cfg[preset].longdbi);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LCRMASK,cfg[preset].lcrmask);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LCRMASK_POLREV,
+ cfg[preset].lcrmask_polrev);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LCRMASK_STATE,
+ cfg[preset].lcrmask_state);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_LCRMASK_LINECAP,
+ cfg[preset].lcrmask_linecap);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VCM_OH,cfg[preset].vcm_oh);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VOV_BAT,cfg[preset].vov_bat);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_VOV_GND,cfg[preset].vov_gnd);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_LINEFEED,lf);
+
+ return RC_NONE;
+}
+
+#endif
+
+/*
+** Function: PROSLIC_PulseMeterSetup
+**
+** Description:
+** configure pulse metering
+*/
+
+#ifndef DISABLE_PULSE_SETUP
+int Si3218x_PulseMeterSetup (proslicChanType *pProslic, int preset)
+{
+ uInt8 reg;
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ else
+ {
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PM_AMP_THRESH,
+ Si3218x_PulseMeter_Presets[preset].pm_amp_thresh);
+ reg = (Si3218x_PulseMeter_Presets[preset].pmFreq<<1)|
+ (Si3218x_PulseMeter_Presets[preset].pmAuto<<3);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PM_ACTIVE,
+ Si3218x_PulseMeter_Presets[preset].pmActive);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_PM_INACTIVE,
+ Si3218x_PulseMeter_Presets[preset].pmInactive);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_PMCON,reg);
+ return RC_NONE;
+ }
+
+}
+#endif
+
+/*
+** Function: PROSLIC_PCMSetup
+**
+** Description:
+** configure pcm
+*/
+
+#ifndef DISABLE_PCM_SETUP
+int Si3218x_PCMSetup(proslicChanType *pProslic, int preset)
+{
+ uInt8 regTemp;
+ uInt8 pmEn;
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ pmEn = ReadReg(pProHW,pProslic->channel,
+ SI3218X_REG_PMCON) & 0x01; /* PM/wideband lockout */
+ if (Si3218x_PCM_Presets[preset].widebandEn && pmEn)
+ {
+#ifdef ENABLE_DEBUG
+ LOGPRINT ("%s Wideband Mode is not supported while Pulse Metering is enabled.\n",
+ LOGPRINT_PREFIX);
+#endif
+ }
+ else if (Si3218x_PCM_Presets[preset].widebandEn && !pmEn)
+ {
+ /* TXIIR settings */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B0_1,0x3538E80L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B1_1,0x3538E80L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A1_1,0x1AA9100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B0_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B1_2,0x2505400L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B2_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A1_2,0x2CB8100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A2_2,0x1D7FA500L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B0_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B1_3,0x1276D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B2_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A1_3,0x2335300L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A2_3,0x19D5F700L);
+ /* RXIIR settings */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B0_1,0x6A71D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B1_1,0x6A71D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A1_1,0x1AA9100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B0_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B1_2,0x2505400L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B2_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A1_2,0x2CB8100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A2_2,0x1D7FA500L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B0_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B1_3,0x1276D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B2_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A1_3,0x2335300L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A2_3,0x19D5F700L);
+ /*
+ ** RXHPF
+ ** Note: Calling ProSLIC_ZsynthSetup() will overwrite some
+ ** of these values. ProSLIC_PCMSetup() should always
+ ** be called after loading coefficients when using
+ ** wideband mode
+ */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_B0_1,0x7CFF900L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_B1_1,0x18300700L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_A1_1,0x79FF201L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_B0_2,0x7CEDA1DL);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_B1_2,0x106320D4L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_B2_2,0x7CEDA1DL);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_A1_2,0xF9A910FL);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_A2_2,0x185FFDA8L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACHPF_GAIN,0x08000000L);
+ /* TXHPF */
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_B0_1,0x0C7FF4CEL);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_B1_1,0x13800B32L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_A1_1,0x079FF201L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_B0_2,0x030FDD10L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_B1_2,0x19E0996CL);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_B2_2,0x030FDD10L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_A1_2,0x0F9A910FL);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_A2_2,0x185FFDA8L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACHPF_GAIN,0x0CD30000L);
+
+ regTemp = ReadReg(pProHW,pProslic->channel,SI3218X_REG_DIGCON);
+#ifndef DISABLE_HPF_WIDEBAND
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_DIGCON,
+ regTemp&~(0xC)); /* Enable HPF */
+#else
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_DIGCON,
+ regTemp|(0xC)); /* Disable HPF */
+#endif
+ regTemp = ReadReg(pProHW,pProslic->channel,SI3218X_REG_ENHANCE);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_ENHANCE,regTemp|1);
+ }
+ else
+ {
+ regTemp = ReadReg(pProHW,pProslic->channel,SI3218X_REG_DIGCON);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_DIGCON,regTemp&~(0xC));
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B0_1,0x3538E80L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B1_1,0x3538E80L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A1_1,0x1AA9100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B0_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B1_2,0x2505400L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B2_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A1_2,0x2CB8100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A2_2,0x1D7FA500L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B0_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B1_3,0x1276D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_B2_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A1_3,0x2335300L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_TXACIIR_A2_3,0x19D5F700L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B0_1,0x6A71D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B1_1,0x6A71D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A1_1,0x1AA9100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B0_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B1_2,0x2505400L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B2_2,0x216D100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A1_2,0x2CB8100L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A2_2,0x1D7FA500L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B0_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B1_3,0x1276D00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_B2_3,0x2CD9B00L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A1_3,0x2335300L);
+ WriteRAM(pProHW,pProslic->channel,SI3218X_RAM_RXACIIR_A2_3,0x19D5F700L);
+ regTemp = ReadReg(pProHW,pProslic->channel,SI3218X_REG_ENHANCE);
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_ENHANCE,regTemp&~(1));
+ }
+ regTemp = Si3218x_PCM_Presets[preset].pcmFormat;
+ regTemp |= Si3218x_PCM_Presets[preset].pcm_tri << 5;
+ regTemp |= Si3218x_PCM_Presets[preset].alaw_inv << 2;
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_PCMMODE,regTemp);
+ regTemp = ReadReg(pProHW,pProslic->channel,SI3218X_REG_PCMTXHI);
+ regTemp &= 3;
+ regTemp |= Si3218x_PCM_Presets[preset].tx_edge<<4;
+ WriteReg(pProHW,pProslic->channel,SI3218X_REG_PCMTXHI,regTemp);
+
+ return RC_NONE;
+}
+#endif
+
+/*
+**
+** PROSLIC CONTROL FUNCTIONS
+**
+*/
+
+/*
+
+** Function: PROSLIC_dbgSetDCFeed
+**
+** Description:
+** provisionally function for setting up
+** dcfeed given desired open circuit voltage
+** and loop current.
+*/
+
+int Si3218x_dbgSetDCFeed (proslicChanType *pProslic, uInt32 v_vlim_val,
+ uInt32 i_ilim_val, int32 preset)
+{
+#ifndef DISABLE_DCFEED_SETUP
+ /* Note: * needs more descriptive return codes in the event of an out of range argument */
+ 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
+ **
+ */
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ /* Validate arguments */
+ 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;
+
+ Si3218x_DCfeed_Presets[preset].slope_vlim = 0x18842BD7L;
+ Si3218x_DCfeed_Presets[preset].slope_rfeed = 0x1E8886DEL;
+ Si3218x_DCfeed_Presets[preset].slope_ilim = 0x40A0E0L;
+ Si3218x_DCfeed_Presets[preset].delta1 = 0x1EABA1BFL;
+ Si3218x_DCfeed_Presets[preset].delta2 = 0x1EF744EAL;
+ Si3218x_DCfeed_Presets[preset].v_vlim = v_vlim_val;
+ Si3218x_DCfeed_Presets[preset].v_rfeed = v_rfeed_val;
+ Si3218x_DCfeed_Presets[preset].v_ilim = v_ilim_val;
+ Si3218x_DCfeed_Presets[preset].const_rfeed = const_rfeed_val;
+ Si3218x_DCfeed_Presets[preset].const_ilim = const_ilim_val;
+ Si3218x_DCfeed_Presets[preset].i_vlim = i_vlim_val;
+
+ return RC_NONE;
+#else
+ SILABS_UNREFERENCED_PARAMETER(pProslic);
+ SILABS_UNREFERENCED_PARAMETER(preset);
+ SILABS_UNREFERENCED_PARAMETER(v_vlim_val);
+ SILABS_UNREFERENCED_PARAMETER(i_ilim_val);
+ return RC_IGNORE;
+#endif
+}
+
+/*
+** Function: PROSLIC_dbgSetDCFeedVopen
+**
+** Description:
+** provisionally function for setting up
+** dcfeed given desired open circuit voltage.
+** Entry I_ILIM value will be used.
+*/
+int Si3218x_dbgSetDCFeedVopen (proslicChanType *pProslic, uInt32 v_vlim_val,
+ int32 preset)
+{
+#ifndef DISABLE_DCFEED_SETUP
+ uInt32 i_ilim_val;
+ uInt32 iscale1 = 913;
+ uInt32 iscale2 = 334; /* 913x334 = 304942 */
+
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ /* Read present CONST_ILIM value */
+ i_ilim_val = Si3218x_DCfeed_Presets[preset].const_ilim;
+
+
+ i_ilim_val /= iscale2;
+ i_ilim_val /= iscale1;
+
+ return Si3218x_dbgSetDCFeed(pProslic,v_vlim_val,i_ilim_val,preset);
+#else
+ SILABS_UNREFERENCED_PARAMETER(pProslic);
+ SILABS_UNREFERENCED_PARAMETER(preset);
+ SILABS_UNREFERENCED_PARAMETER(v_vlim_val);
+ return RC_IGNORE;
+#endif
+}
+
+/*
+** Function: PROSLIC_dbgSetDCFeedIloop
+**
+** Description:
+** provisionally function for setting up
+** dcfeed given desired loop current.
+** Entry V_VLIM value will be used.
+*/
+int Si3218x_dbgSetDCFeedIloop (proslicChanType *pProslic, uInt32 i_ilim_val,
+ int32 preset)
+{
+#ifndef DISABLE_DCFEED_SETUP
+
+ uInt32 v_vlim_val;
+ uInt32 vscale1 = 1386;
+ uInt32 vscale2 =
+ 1422; /* 1386x1422 = 1970892 broken down to minimize trunc err */
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ /* Read present V_VLIM value */
+ v_vlim_val = Si3218x_DCfeed_Presets[preset].v_vlim;
+
+ v_vlim_val /= vscale2;
+ v_vlim_val /= vscale1;
+
+ return Si3218x_dbgSetDCFeed(pProslic,v_vlim_val,i_ilim_val, preset);
+#else
+ SILABS_UNREFERENCED_PARAMETER(pProslic);
+ SILABS_UNREFERENCED_PARAMETER(preset);
+ SILABS_UNREFERENCED_PARAMETER(i_ilim_val);
+ return RC_IGNORE;
+#endif
+}
+
+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;
+
+static 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 */
+
+static 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, 0L, 0L}
+ }; /* terminator */
+
+static 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 */
+ };
+
+
+static 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 */
+ };
+
+/*
+** Function: PROSLIC_dbgRingingSetup
+**
+** Description:
+** Provision function for setting up
+** Ring type, frequency, amplitude and dc offset.
+** Main use will be by peek/poke applications.
+*/
+int Si3218x_dbgSetRinging (proslicChanType *pProslic,
+ ProSLIC_dbgRingCfg *ringCfg, int preset)
+{
+#ifndef DISABLE_RING_SETUP
+ int errVal,i=0;
+ uInt32 vScale = 1608872L; /* (2^28/170.25)*((100+4903)/4903) */
+ ramData dcdcVminTmp;
+
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ errVal = RC_NONE;
+
+ 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 = RC_RING_V_LIMITED;
+ }
+
+ /* Update RINGFR RINGAMP, RINGOFFSET, and RINGCON */
+ Si3218x_Ring_Presets[preset].freq = sineRingFreqTable[i].ringfr;
+ Si3218x_Ring_Presets[preset].amp = ringCfg->amp * sineRingFreqTable[i].ampScale;
+ Si3218x_Ring_Presets[preset].offset = ringCfg->offset * vScale;
+ Si3218x_Ring_Presets[preset].phas = 0L;
+
+ /* Don't alter anything in RINGCON other than clearing the TRAP bit */
+ Si3218x_Ring_Presets[preset].ringcon &= 0xFE;
+
+ Si3218x_Ring_Presets[preset].rtper = sineRingtripTable[i].rtper;
+ Si3218x_Ring_Presets[preset].rtacdb = sineRingtripTable[i].rtdb;
+ Si3218x_Ring_Presets[preset].rtdcdb = sineRingtripTable[i].rtdb;
+ Si3218x_Ring_Presets[preset].rtdcth = 0xFFFFFFFL;
+ Si3218x_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 = RC_RING_V_LIMITED;
+ }
+
+ /* Update RINGFR RINGAMP, RINGOFFSET, and RINGCON */
+ Si3218x_Ring_Presets[preset].amp = ringCfg->amp * vScale;
+ Si3218x_Ring_Presets[preset].freq =
+ Si3218x_Ring_Presets[preset].amp/trapRingFreqTable[i].cfVal[ringCfg->ringtype];
+ Si3218x_Ring_Presets[preset].offset = ringCfg->offset * vScale;
+ Si3218x_Ring_Presets[preset].phas = 262144000L/trapRingFreqTable[i].freq;
+
+ /* Don't alter anything in RINGCON other than setting the TRAP bit */
+ Si3218x_Ring_Presets[preset].ringcon |= 0x01;
+
+ /* RTPER and debouce timers */
+ Si3218x_Ring_Presets[preset].rtper = trapRingtripTable[i].rtper;
+ Si3218x_Ring_Presets[preset].rtacdb = trapRingtripTable[i].rtdb;
+ Si3218x_Ring_Presets[preset].rtdcdb = trapRingtripTable[i].rtdb;
+
+
+ Si3218x_Ring_Presets[preset].rtdcth = 0xFFFFFFFL;
+ Si3218x_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)
+ ||(Si3218x_General_Configuration.bom_option == BO_DCDC_BUCK_BOOST))
+ {
+ dcdcVminTmp = ringCfg->amp + ringCfg->offset;
+ dcdcVminTmp *= 1000;
+ dcdcVminTmp *= SCALE_V_MADC;
+ Si3218x_Ring_Presets[preset].dcdc_vref_min_rng = dcdcVminTmp;
+ }
+ else
+ {
+ Si3218x_Ring_Presets[preset].dcdc_vref_min_rng = 0x1800000L;
+ }
+
+ return errVal;
+#else
+ SILABS_UNREFERENCED_PARAMETER(pProslic);
+ SILABS_UNREFERENCED_PARAMETER(preset);
+ SILABS_UNREFERENCED_PARAMETER(ringCfg);
+ return RC_IGNORE;
+#endif
+}
+
+
+typedef struct
+{
+ int32 gain;
+ uInt32 scale;
+} ProSLIC_GainScaleLookup;
+
+#ifndef ENABLE_HIRES_GAIN
+static int Si3218x_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 */
+ };
+
+ SILABS_UNREFERENCED_PARAMETER(pProslic);
+
+ /* Test against max gain */
+ if (gain > PROSLIC_EXTENDED_GAIN_MAX)
+ {
+ errVal = RC_GAIN_OUT_OF_RANGE;
+ DEBUG_PRINT(pProslic, "%sdbgSetGain: Gain %d out of range\n", LOGPRINT_PREFIX,
+ (int)gain);
+ gain = PROSLIC_EXTENDED_GAIN_MAX; /* Clamp to maximum */
+ }
+
+ /* Test against min gain */
+ if (gain < PROSLIC_GAIN_MIN)
+ {
+ errVal = RC_GAIN_OUT_OF_RANGE;
+ DEBUG_PRINT(pProslic, "%sdbgSetGain: Gain %d out of range\n", LOGPRINT_PREFIX,
+ (int)gain);
+ gain = PROSLIC_GAIN_MIN; /* Clamp to minimum */
+ }
+
+ /* Distribute gain */
+ if(gain == 0)
+ {
+ gain_pga = 0;
+ gain_eq = 0;
+ }
+ else if(gain > PROSLIC_GAIN_MAX)
+ {
+ if(tx_rx_sel == TXACGAIN_SEL)
+ {
+ gain_pga = PROSLIC_GAIN_MAX;
+ gain_eq = gain - PROSLIC_GAIN_MAX;
+ }
+ else
+ {
+ gain_pga = gain - PROSLIC_GAIN_MAX;
+ gain_eq = PROSLIC_GAIN_MAX;
+ }
+ }
+ 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 Appropriate PGA Gain
+ */
+ i=0;
+ do
+ {
+ if(gainScaleTable[i].gain >= gain_pga) /* was gain_1 */
+ {
+ 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)
+ {
+ Si3218x_audioGain_Presets[0].acgain =
+ (Si3218x_Impedance_Presets[impedance_preset].txgain/1000)
+ *gainScaleTable[i].scale;
+ }
+ else
+ {
+ Si3218x_audioGain_Presets[1].acgain =
+ (Si3218x_Impedance_Presets[impedance_preset].rxgain/1000)
+ *gainScaleTable[i].scale;
+ }
+
+
+ /*
+ ** Lookup EQ Gain
+ */
+ i=0;
+ do
+ {
+ if(gainScaleTable[i].gain >= gain_eq) /* was gain_2 */
+ {
+ 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 (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 |= 0xf0000000L;
+ }
+
+ Si3218x_audioGain_Presets[0].aceq_c0 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0/1000)
+ *gainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[0].aceq_c1 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1/1000)
+ *gainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[0].aceq_c2 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2/1000)
+ *gainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[0].aceq_c3 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3/1000)
+ *gainScaleTable[i].scale;
+ }
+ else
+ {
+ /*sign extend negative numbers*/
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 |= 0xf0000000L;
+ }
+
+ Si3218x_audioGain_Presets[1].aceq_c0 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0/1000)
+ *gainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[1].aceq_c1 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1/1000)
+ *gainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[1].aceq_c2 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2/1000)
+ *gainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[1].aceq_c3 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3/1000)
+ *gainScaleTable[i].scale;
+ }
+
+
+ return errVal;
+}
+#else /* ENABLE_HIRES_GAIN */
+/*
+** Function: Si3218x_dbgSetGainHiRes()
+**
+** Description:
+** Provision function for setting up
+** TX and RX gain with 0.1dB resolution instead
+** of 1.0dB resolution
+*/
+static int Si3218x_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 */
+ };
+
+ SILABS_UNREFERENCED_PARAMETER(pProslic);
+
+ /* Test against max gain */
+ if (gain > (PROSLIC_GAIN_MAX*10L))
+ {
+ errVal = RC_GAIN_OUT_OF_RANGE;
+ DEBUG_PRINT(pProslic, "%sdbgSetGain: Gain %d dB*10 out of range\n",
+ LOGPRINT_PREFIX, gain);
+ gain = (PROSLIC_GAIN_MAX*10L); /* Clamp to maximum */
+ }
+
+ /* Test against min gain */
+ if (gain < (PROSLIC_GAIN_MIN*10L))
+ {
+ errVal = RC_GAIN_OUT_OF_RANGE;
+ DEBUG_PRINT(pProslic, "%sdbgSetGain: Gain %d dB*10 out of range\n",
+ LOGPRINT_PREFIX, gain);
+ gain = (PROSLIC_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)
+ {
+ Si3218x_audioGain_Presets[0].acgain = ((
+ Si3218x_Impedance_Presets[impedance_preset].txgain/1000L)
+ *coarseGainScaleTable[coarseGainIndex].scale);
+ }
+ else
+ {
+ Si3218x_audioGain_Presets[1].acgain = ((
+ Si3218x_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 (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3 |= 0xf0000000L;
+ }
+
+ tmp = (((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c0/1000L)
+ *coarseGainScaleTable[coarseGainIndex].scale);
+ tmp = tmp / (int32)1000L;
+ tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
+ Si3218x_audioGain_Presets[0].aceq_c0 = tmp;
+
+ tmp = (((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c1/1000L)
+ *coarseGainScaleTable[coarseGainIndex].scale);
+ tmp = tmp / (int32)1000L;
+ tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
+ Si3218x_audioGain_Presets[0].aceq_c1 = tmp;
+
+ tmp = (((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c2/1000L)
+ *coarseGainScaleTable[coarseGainIndex].scale);
+ tmp = tmp / (int32)1000L;
+ tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
+ Si3218x_audioGain_Presets[0].aceq_c2 = tmp;
+
+ tmp = (((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.txaceq_c3/1000L)
+ *coarseGainScaleTable[coarseGainIndex].scale);
+ tmp = tmp / (int32)1000L;
+ tmp = tmp * (int32)fineGainScaleTable[fineGainIndex].scale;
+ Si3218x_audioGain_Presets[0].aceq_c3 = tmp;
+ }
+ else
+ {
+ /*sign extend negative numbers*/
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2 |= 0xf0000000L;
+ }
+ if (Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 & 0x10000000L)
+ {
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3 |= 0xf0000000L;
+ }
+
+ Si3218x_audioGain_Presets[1].aceq_c0 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c0/1000)
+ *coarseGainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[1].aceq_c1 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c1/1000)
+ * coarseGainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[1].aceq_c2 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c2/1000)
+ * coarseGainScaleTable[i].scale;
+ Si3218x_audioGain_Presets[1].aceq_c3 = ((int32)
+ Si3218x_Impedance_Presets[impedance_preset].audioEQ.rxaceq_c3/1000)
+ * coarseGainScaleTable[i].scale;
+ }
+
+ return errVal;
+}
+#endif /* ENABLE_HIRES_GAIN */
+
+/*
+** Function: PROSLIC_dbgSetTXGain
+**
+** Description:
+** Provision function for setting up
+** TX gain
+*/
+
+int Si3218x_dbgSetTXGain (proslicChanType *pProslic, int32 gain,
+ int impedance_preset, int audio_gain_preset)
+{
+ SILABS_UNREFERENCED_PARAMETER(audio_gain_preset);
+#ifdef ENABLE_HIRES_GAIN
+ return Si3218x_dbgSetGainHiRes(pProslic,gain,impedance_preset,TXACGAIN_SEL);
+#else
+ return Si3218x_dbgSetGain(pProslic,gain,impedance_preset,TXACGAIN_SEL);
+#endif
+}
+
+/*
+** Function: PROSLIC_dbgSetRXGain
+**
+** Description:
+** Provision function for setting up
+** RX gain
+*/
+int Si3218x_dbgSetRXGain (proslicChanType *pProslic, int32 gain,
+ int impedance_preset, int audio_gain_preset)
+{
+ SILABS_UNREFERENCED_PARAMETER(audio_gain_preset);
+#ifdef ENABLE_HIRES_GAIN
+ return Si3218x_dbgSetGainHiRes(pProslic,gain,impedance_preset,RXACGAIN_SEL);
+#else
+ return Si3218x_dbgSetGain(pProslic,gain,impedance_preset,RXACGAIN_SEL);
+#endif
+}
+
+/*
+** Function: Si3218x_GetRAMScale
+**
+** Description:
+** Read scale factor for passed RAM location
+**
+** Return Value:
+** int32 scale
+*/
+static int32 Si3218x_GetRAMScale(uInt16 addr)
+{
+ int32 scale;
+
+ switch(addr)
+ {
+ case SI3218X_RAM_MADC_ILOOP:
+ case SI3218X_RAM_MADC_ITIP:
+ case SI3218X_RAM_MADC_IRING:
+ case SI3218X_RAM_MADC_ILONG:
+ scale = SCALE_I_MADC;
+ break;
+
+ case SI3218X_RAM_MADC_VTIPC:
+ case SI3218X_RAM_MADC_VRINGC:
+ case SI3218X_RAM_MADC_VBAT:
+ case SI3218X_RAM_MADC_VDC:
+ case SI3218X_RAM_MADC_VDC_OS:
+ case SI3218X_RAM_MADC_VLONG:
+ case SI3218X_RAM_VDIFF_SENSE:
+ case SI3218X_RAM_VDIFF_FILT:
+ case SI3218X_RAM_VDIFF_COARSE:
+ case SI3218X_RAM_VTIP:
+ case SI3218X_RAM_VRING:
+ scale = SCALE_V_MADC;
+ break;
+
+ default:
+ scale = 1;
+ break;
+ }
+
+ return scale;
+}
+
+/*
+** Function: Si3218x_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 Si3218x_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 = Si3218x_GetRAMScale(addr);
+ }
+
+ data /= scale;
+
+ return data;
+}
+
+/*
+** Function: Si3218x_LineMonitor
+**
+** Description:
+** Monitor line voltages and currents
+*/
+int Si3218x_LineMonitor(proslicChanType *pProslic, proslicMonitorType *monitor)
+{
+
+ if(pProslic->channelType != PROSLIC)
+ {
+ return RC_CHANNEL_TYPE_ERR;
+ }
+
+ if(pProslic->channelEnable)
+ {
+ monitor->vtr = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_VDIFF_FILT);
+ if(monitor->vtr & 0x10000000L)
+ {
+ monitor->vtr |= 0xf0000000L;
+ }
+ monitor->vtr /= SCALE_V_MADC;
+
+ monitor->vtip = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_VTIP);
+ if(monitor->vtip & 0x10000000L)
+ {
+ monitor->vtip |= 0xf0000000L;
+ }
+ monitor->vtip /= SCALE_V_MADC;
+
+ monitor->vring = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_VRING);
+ if(monitor->vring & 0x10000000L)
+ {
+ monitor->vring |= 0xf0000000L;
+ }
+ monitor->vring /= SCALE_V_MADC;
+
+ monitor->vlong = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_VLONG);
+ if(monitor->vlong & 0x10000000L)
+ {
+ monitor->vlong |= 0xf0000000L;
+ }
+ monitor->vlong /= SCALE_V_MADC;
+
+ monitor->vbat = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_VBAT);
+ if(monitor->vbat & 0x10000000L)
+ {
+ monitor->vbat |= 0xf0000000L;
+ }
+ monitor->vbat /= SCALE_V_MADC;
+
+ monitor->vdc = 0; /* Si3218x has no SVDC */
+
+ monitor->itr = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_ILOOP);
+ if(monitor->itr & 0x10000000L)
+ {
+ monitor->itr |= 0xf0000000L;
+ }
+ monitor->itr /= SCALE_I_MADC;
+
+ monitor->itip = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_ITIP);
+ if(monitor->itip & 0x10000000L)
+ {
+ monitor->itip |= 0xf0000000L;
+ }
+ monitor->itip /= SCALE_I_MADC;
+
+ monitor->iring = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_IRING);
+ if(monitor->iring & 0x10000000L)
+ {
+ monitor->iring |= 0xf0000000L;
+ }
+ monitor->iring /= SCALE_I_MADC;
+
+ monitor->ilong = ReadRAM(pProHW,pProslic->channel,SI3218X_RAM_MADC_ILONG);
+ if(monitor->ilong & 0x10000000L)
+ {
+ monitor->ilong |= 0xf0000000L;
+ }
+ monitor->ilong /= SCALE_I_MADC;
+
+ monitor->p_hvic = ReadRAM(pProHW,pProslic->channel,
+ SI3218X_RAM_P_Q1_D); /* P_HVIC_LPF */
+ if(monitor->p_hvic & 0x10000000L)
+ {
+ monitor->p_hvic |= 0xf0000000L;
+ }
+ monitor->p_hvic /= SCALE_P_MADC;
+ }
+
+ return RC_NONE;
+}
+
+/*
+** Function: Si3218x_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).
+**
+*/
+int Si3218x_PSTNCheck (proslicChanType *pProslic,
+ proslicPSTNCheckObjType *pPSTNCheck)
+{
+ uInt8 i;
+
+ if( (pProslic->channelType != PROSLIC)
+ || (pPSTNCheck->samples == 0) )
+ {
+ return RC_NONE; /* Ignore DAA channels */
+ }
+
+ /* 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,
+ SI3218X_RAM_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 RC_PSTN_CHECK_SINGLE_FAIL; /* 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 RC_PSTN_CHECK_AVG_FAIL;
+ }
+ else
+ {
+ pPSTNCheck->count++;
+ return RC_NONE;
+ }
+ }
+ else
+ {
+ pPSTNCheck->count++;
+ return RC_NONE;
+ }
+}
+
+#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: Si3218x_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_POWER_ALARM_HVIC - test interrupted by HVIC power alarm
+** RC_
+**
+*/
+
+int Si3218x_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, PROSLIC_REG_ENHANCE);
+ WriteReg(pProHW,pProslic->channel, PROSLIC_REG_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 */
+ Si3218x_ReadHookStatus(pProslic,&loop_status);
+ if((loop_status == PROSLIC_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, PROSLIC_REG_LINEFEED);
+ ProSLIC_SetLinefeedStatus(pProslic,LF_OPEN);
+ pPSTNCheck->pState.stage++;
+ return RC_NONE;
+
+ case 2:
+ /* Settle */
+ ProSLIC_PSTN_delay_poll(&(pPSTNCheck->pState), PSTN_DET_OPEN_FEMF_SETTLE);
+ return RC_NONE;
+
+ case 3:
+ /* Measure HAZV */
+ pPSTNCheck->vdiff_open = Si3218x_ReadMADCScaled(pProslic,SI3218X_RAM_VDIFF_COARSE,0);
+ DEBUG_PRINT(pProslic, "%sDiff PSTN : Vopen = %d mV\n", LOGPRINT_PREFIX,
+ pPSTNCheck->vdiff_open);
+
+ /* Stop PSTN check if differential voltage > max_femf_vopen present */
+ 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 */
+ ProSLIC_PSTN_delay_poll(&(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] =
+ Si3218x_ReadMADCScaled(pProslic,SI3218X_RAM_VDIFF_FILT,0);
+ pPSTNCheck->iloop1[pPSTNCheck->pState.sampleIterations] =
+ Si3218x_ReadMADCScaled(pProslic,SI3218X_RAM_MADC_ILOOP,0);
+#ifdef ENABLE_DEBUG
+ if ( DEBUG_ENABLED(pProslic) )
+ {
+ LOGPRINT("%sDiff PSTN: Vdiff1[%d] = %d mV\n", LOGPRINT_PREFIX,
+ pPSTNCheck->pState.sampleIterations,
+ pPSTNCheck->vdiff1[pPSTNCheck->pState.sampleIterations]);
+ LOGPRINT("%sDiff PSTN: Iloop1[%d] = %d uA\n", LOGPRINT_PREFIX,
+ 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 */
+ ProSLIC_PSTN_delay_poll(&(pPSTNCheck->pState), PSTN_DET_DIFF_IV2_SETTLE);
+ return RC_NONE;
+
+ case 14:
+ /* Measure VDIFF and ILOOP*/
+ pPSTNCheck->vdiff2[pPSTNCheck->pState.sampleIterations] =
+ Si3218x_ReadMADCScaled(pProslic,SI3218X_RAM_VDIFF_FILT,0);
+ pPSTNCheck->iloop2[pPSTNCheck->pState.sampleIterations] =
+ Si3218x_ReadMADCScaled(pProslic,SI3218X_RAM_MADC_ILOOP,0);
+#ifdef ENABLE_DEBUG
+ if ( DEBUG_ENABLED(pProslic) )
+ {
+ LOGPRINT("%sDiff PSTN: Vdiff2[%d] = %d mV\n", LOGPRINT_PREFIX,
+ pPSTNCheck->pState.sampleIterations,
+ pPSTNCheck->vdiff2[pPSTNCheck->pState.sampleIterations]);
+ LOGPRINT("%sDiff PSTN: Iloop2[%d] = %d uA\n", LOGPRINT_PREFIX,
+ 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 ( DEBUG_ENABLED(pProslic) )
+ {
+ const char fmt_string[] = "%sDiffPSTN: %s = %d %s\n";
+ LOGPRINT(fmt_string, LOGPRINT_PREFIX, "VDIFF1", pPSTNCheck->vdiff1_avg, "mV");
+ LOGPRINT(fmt_string, LOGPRINT_PREFIX, "ILOOP1",pPSTNCheck->iloop1_avg, "uA");
+ LOGPRINT(fmt_string, LOGPRINT_PREFIX, "VDIFF2",pPSTNCheck->vdiff2_avg, "mV");
+ LOGPRINT(fmt_string, LOGPRINT_PREFIX, "ILOOP2",pPSTNCheck->iloop2_avg, "uA");
+ LOGPRINT(fmt_string, LOGPRINT_PREFIX, "RL1",pPSTNCheck->rl1, "ohm");
+ LOGPRINT(fmt_string, LOGPRINT_PREFIX, "RL2",pPSTNCheck->rl2, "ohm");
+ LOGPRINT(fmt_string, LOGPRINT_PREFIX, "RL_Ratio",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);
+ WriteReg(pProHW,pProslic->channel,PROSLIC_REG_ENHANCE, pPSTNCheck->enhanceRegSave);
+ pPSTNCheck->pState.stage = 0;
+ pPSTNCheck->pState.waitIterations = 0;
+ pPSTNCheck->pState.sampleIterations = 0;
+ return pPSTNCheck->return_status;
+
+ }
+ return RC_NONE;
+}
+
+#endif
+