[][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/Makefile b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/Makefile
new file mode 100644
index 0000000..d9063fd
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/Makefile
@@ -0,0 +1,18 @@
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+# platform driver
+subdir-ccflags-y += -I../inc
+subdir-ccflags-y += -DSI3218X
+subdir-ccflags-y += -DPROSLIC_LINUX_KERNEL
+snd-soc-procslic-common-objs := proslic.o proslic_tstin.o si_voice.o si_voice_version.o si3218x_intf.o vdaa.o si3217x_intf.o si3217x_revb_intf.o si3217x_revc_intf.o si3219x_intf.o si3226x_intf.o si3228x_intf.o
+
+obj-$(CONFIG_SND_SOC_SI3218X) += snd-soc-proslic-common.o
diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/proslic.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/proslic.c
new file mode 100644
index 0000000..7a75cc8
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/proslic.c
@@ -0,0 +1,4651 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 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 generic interface file for the ProSLIC drivers.
+ *
+ * Customers should be calling this level for ProSLIC specific
+ * functions (vs. chipset specific versions of the code)
+ *
+ */
+
+#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 "../config_inc/proslic_api_config.h"
+
+#ifdef ENABLE_DEBUG
+#define LOGPRINT_PREFIX "ProSLIC:"
+#endif
+
+#ifdef SI3217X
+#include "si3217x.h"
+#include "si3217x_intf.h"
+extern Si3217x_General_Cfg Si3217x_General_Configuration;
+#ifndef DISABLE_FSK_SETUP
+extern ProSLIC_FSK_Cfg Si3217x_FSK_Presets[];
+#endif
+#ifndef DISABLE_TONE_SETUP
+extern ProSLIC_Tone_Cfg Si3217x_Tone_Presets[];
+#endif
+
+#endif /* 17X */
+
+#ifdef SI3218X
+#include "../inc/si3218x.h"
+#include "../inc/si3218x_intf.h"
+extern Si3218x_General_Cfg Si3218x_General_Configuration;
+#ifndef DISABLE_FSK_SETUP
+extern ProSLIC_FSK_Cfg Si3218x_FSK_Presets[];
+#endif
+#ifndef DISABLE_TONE_SETUP
+extern ProSLIC_Tone_Cfg Si3218x_Tone_Presets[];
+#endif
+#endif /* 18X */ 
+
+#ifdef SI3219X
+#include "si3219x.h"
+#include "si3219x_intf.h"
+extern Si3219x_General_Cfg Si3219x_General_Configuration;
+#ifndef DISABLE_FSK_SETUP
+extern ProSLIC_FSK_Cfg Si3219x_FSK_Presets[];
+#endif
+#ifndef DISABLE_TONE_SETUP
+extern ProSLIC_Tone_Cfg Si3219x_Tone_Presets[];
+#endif
+#endif /* 19X */
+
+#ifdef SI3226X
+#include "si3226x.h"
+#include "si3226x_intf.h"
+extern Si3226x_General_Cfg Si3226x_General_Configuration;
+#ifndef DISABLE_FSK_SETUP
+extern ProSLIC_FSK_Cfg Si3226x_FSK_Presets[];
+#endif
+#ifndef DISABLE_TONE_SETUP
+extern ProSLIC_Tone_Cfg Si3226x_Tone_Presets[];
+#endif
+#endif /* 26X */
+
+#ifdef SI3228X
+#include "si3228x.h"
+#include "si3228x_intf.h"
+extern Si3228x_General_Cfg Si3228x_General_Configuration;
+#ifndef DISABLE_FSK_SETUP
+extern ProSLIC_FSK_Cfg Si3228x_FSK_Presets[];
+#endif
+#ifndef DISABLE_TONE_SETUP
+extern ProSLIC_Tone_Cfg Si3228x_Tone_Presets[];
+#endif
+
+#endif /* 28X */
+
+#define pCtrl(X)                                   (X)->deviceId->ctrlInterface
+#define pProHW(X)                                  pCtrl((X))->hCtrl
+#define WriteRAM(PCHAN, CHANNEL, RAMADDR, RAMDATA) (PCHAN)->deviceId->ctrlInterface->WriteRAM_fptr(pProHW(PCHAN), (CHANNEL), (RAMADDR), (RAMDATA))
+#define ReadRAM(PCHAN, CHANNEL, RAMADDR)           (PCHAN)->deviceId->ctrlInterface->ReadRAM_fptr(pProHW(PCHAN), (CHANNEL), (RAMADDR))
+#define SetSemaphore(X)                            (X)->deviceId->ctrlInterface->Semaphore_fptr
+#define ReadReg(PCHAN, CHANNEL, REGADDR)           (PCHAN)->deviceId->ctrlInterface->ReadRegister_fptr(pProHW(PCHAN), (CHANNEL), (REGADDR))
+#define WriteReg(PCHAN, CHANNEL, REGADDR, REGDATA) (PCHAN)->deviceId->ctrlInterface->WriteRegister_fptr(pProHW(PCHAN), (CHANNEL), (REGADDR), (REGDATA))
+
+/*
+** Timers
+*/
+#define TimeElapsed   pProslic->deviceId->ctrlInterface->timeElapsed_fptr
+#define getTime       pProslic->deviceId->ctrlInterface->getTime_fptr
+#define pProTimer	    pProslic->deviceId->ctrlInterface->hTimer
+#define Delay         pProslic->deviceId->ctrlInterface->Delay_fptr
+#define pProTimerX(X)	((X)->deviceId->ctrlInterface->hTimer)
+#define DelayX(X,Y)   ((X)->deviceId->ctrlInterface->Delay_fptr(pProTimerX(X),Y))
+
+#define PROSLIC_TIMEOUT_DCDC_DOWN 200 /* Number of 10 mSec ticks */
+
+/*****************************************************************************************************/
+int32 ProSLIC_ReadMADCScaled(proslicChanType_ptr hProslic,uInt16 addr,
+                             int32 scale)
+{
+  TRACEPRINT(hProslic,"addr: %u scale: %ld\n", addr, scale);
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_ReadMADCScaled(hProslic,addr,scale);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_ReadMADCScaled(hProslic,addr,scale);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_ReadMADCScaled(hProslic,addr,scale);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_ReadMADCScaled(hProslic,addr,scale);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_ReadMADCScaled(hProslic,addr,scale);
+  }
+#endif
+
+  return -1;
+}
+
+/*****************************************************************************************************/
+ramData ProSLIC_ReadRAM(proslicChanType_ptr hProslic,uInt16 addr)
+{
+  TRACEPRINT(hProslic, "addr: %u\n", addr);
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  return (ReadRAM(hProslic, hProslic->channel, addr));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_WriteRAM(proslicChanType_ptr hProslic,uInt16 addr, ramData data)
+{
+  TRACEPRINT(hProslic, "addr: %u data: 0x%04X\n", addr, data);
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  return (WriteRAM(hProslic, hProslic->channel, addr,data));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PrintDebugData(proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+#ifdef ENABLE_DEBUG
+  ProSLIC_PrintDebugReg(hProslic);
+  return ProSLIC_PrintDebugRAM(hProslic);
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  return RC_NONE;
+#endif
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PrintDebugReg(proslicChanType_ptr hProslic)
+{
+#ifdef ENABLE_DEBUG
+  uInt8 regAddr;
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  /*
+     NOTE: Not all ProSLICs have defined values after location 99
+     (and have 1 location after that), but for simplicity, we print them anyway...
+  */
+  for(regAddr = 0; regAddr < 127; regAddr++)
+  {
+    LOGPRINT("%sRegister %03u = 0x%02X\n", LOGPRINT_PREFIX, regAddr,
+             ReadReg(hProslic, hProslic->channel, regAddr));
+  }
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+#endif
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+/* NOTE: locations above 1024 are protected, the API disables protection during initialization, but if this
+   function is called prior to initialization, then UAM is not set and will impact the ReadRAM call...
+   Upper limit is based upon chipset type...
+*/
+int ProSLIC_PrintDebugRAM(proslicChanType_ptr hProslic)
+{
+#ifdef ENABLE_DEBUG
+  uInt16 ramAddr;
+  uInt16 maxAddr= 0;
+  TRACEPRINT(hProslic, "\n",NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    maxAddr = 1596;
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    maxAddr = 1644;
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    maxAddr = 1644;
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    maxAddr = 1646;
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    maxAddr = 1646;
+  }
+#endif
+
+  for(ramAddr = 0; ramAddr < maxAddr; ramAddr++)
+  {
+    LOGPRINT("%sRAM %04u = 0x%08X\n", LOGPRINT_PREFIX, ramAddr,
+             (unsigned int)(ReadRAM(hProslic, hProslic->channel, ramAddr)));
+  }
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+#endif /* ENABLE_DEBUG */
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: isVerifiedProslic
+**
+** Description:
+** Determine if DAA or ProSLIC present
+**
+** Input Parameters:
+** pProslic: pointer to PROSLIC channel object
+**
+** Return:
+** channelType
+*/
+int ProSLIC_identifyChannelType(proslicChanType *pProslic)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "\n",NULL);
+  /*
+  **  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(pProslic,pProslic->channel,PROSLIC_REG_PCMTXHI,0x13);
+  Delay(pProTimer,5);
+
+  /* Now check if the value took */
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_PCMTXHI);
+
+  if( data == 0x13)
+  {
+    return PROSLIC;
+  }
+  else if (data == 0x40)
+  {
+    return DAA;
+  }
+  else
+  {
+    return UNKNOWN;
+  }
+}
+
+/*****************************************************************************************************/
+int ProSLIC_VerifyControlInterface(proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n",NULL);
+  if (ProSLIC_identifyChannelType(hProslic) != PROSLIC)
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+
+  /* Note: ProSLIC_identifyChannelType() did a register w/r test earlier */
+
+  /* Verify RAM rd/wr with innocuous RAM location */
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_VERIFY_IO,0x12345678L);
+  if (ReadRAM(hProslic,hProslic->channel, PROSLIC_RAM_VERIFY_IO) != 0x12345678L)
+  {
+    hProslic->error = RC_SPI_FAIL;
+    DEBUG_PRINT(hProslic, "%sProslic %d RAM not communicating. RAM access fail.\n",
+                LOGPRINT_PREFIX, hProslic->channel);
+    return RC_SPI_FAIL;
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_VerifyMasterStat(proslicChanType_ptr pProslic)
+{
+  uInt8 regData;
+
+  TRACEPRINT(pProslic, "\n", NULL);
+  WriteReg(pProslic,pProslic->channel, PROSLIC_REG_MSTRSTAT,
+           0xFF); /* Clear Master status */
+  regData = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_MSTRSTAT);
+
+  if( regData != 0x1F )
+  {
+    return RC_SPI_FAIL;
+  }
+  else
+  {
+    return RC_NONE;
+  }
+}
+
+/*****************************************************************************************************/
+#ifdef SIVOICE_MULTI_BOM_SUPPORT
+int ProSLIC_Init_MultiBOM (proslicChanType_ptr *hProslic,int size, int preset)
+{
+  TRACEPRINT(*hProslic, "size: %d preset: %d\n", size, preset);
+#ifdef SI3217X
+  if ((*hProslic)->deviceId->chipType >= SI32171
+      && (*hProslic)->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_Init_MultiBOM(hProslic,size,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if ((*hProslic)->deviceId->chipType >= SI32180
+      && (*hProslic)->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_Init_MultiBOM(hProslic,size,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X((*hProslic)->deviceId) )
+  {
+    return Si3219x_Init_MultiBOM(hProslic,size,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if ((*hProslic)->deviceId->chipType >= SI32260
+      && (*hProslic)->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_Init_MultiBOM(hProslic,size,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if ((*hProslic)->deviceId->chipType >= SI32280
+      && (*hProslic)->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_Init_MultiBOM(hProslic,size,preset);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+int ProSLIC_Init (proslicChanType_ptr *hProslic,int size)
+{
+  TRACEPRINT(*hProslic, "size: %d\n", size);
+  return ProSLIC_Init_with_Options(hProslic, size, INIT_NO_OPT);
+}
+
+/*****************************************************************************************************/
+int ProSLIC_Reinit (proslicChanType_ptr *hProslic,int size)
+{
+  TRACEPRINT(*hProslic, "size: %d\n", size);
+  return ProSLIC_Init_with_Options(hProslic, size, INIT_REINIT);
+}
+
+/*****************************************************************************************************/
+int ProSLIC_Init_with_Options (proslicChanType_ptr *hProslic,int size,
+                               int option)
+{
+  TRACEPRINT(*hProslic, "size: %d option: %d\n", size, option);
+#ifdef SI3226X
+  if ((*hProslic)->deviceId->chipType >= SI32260
+      && (*hProslic)->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_Init_with_Options(hProslic,size, option);
+  }
+#endif
+
+#ifdef SI3228X
+  if ((*hProslic)->deviceId->chipType >= SI32280
+      && (*hProslic)->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_Init_with_Options(hProslic,size, option);
+  }
+#endif
+
+#ifdef SI3217X
+  if ((*hProslic)->deviceId->chipType >= SI32171
+      && (*hProslic)->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_Init_with_Options(hProslic,size, option);
+  }
+#endif
+
+#ifdef SI3218X
+  if ((*hProslic)->deviceId->chipType >= SI32180
+      && (*hProslic)->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_Init_with_Options(hProslic,size, option);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X((*hProslic)->deviceId) )
+  {
+    return Si3219x_Init_with_Options(hProslic,size, option);
+  }
+#endif
+
+  return RC_IGNORE;
+}
+
+/*****************************************************************************************************/
+#if defined(SI3217X) || defined(SI3218X) || defined SI3226X || defined SI3228X || defined(SI3219X)
+/* Check patch data - returns TRUE if no error.*/
+static BOOLEAN ProSLIC_VerifyPatchData(proslicChanType *pProslic,
+                                       const ramData *data, uInt16 maxCount )
+{
+  int loop;
+  ramData read_data;
+  TRACEPRINT(pProslic, "dataptr: %p, count: %d\n", data, maxCount);
+
+  for(loop = 0; loop < maxCount; loop++)
+  {
+    if(*data)
+    {
+      read_data = ReadRAM(pProslic, pProslic->channel, PROSLIC_RAM_PRAM_DATA);
+      if( ((*data) << 9) != read_data)
+      {
+        return FALSE;
+      }
+    }
+    else
+    {
+      break;
+    }
+    data++;
+  }
+  return TRUE;
+}
+
+/* Check if the jump table is written correctly.. */
+static BOOLEAN ProSLIC_VerifyPatchJMPLow(proslicChanType *pProslic,
+    const uInt16 *data)
+{
+  uInt8 address = PATCH_JMPTBL_START_ADDR;
+  int regData;
+
+  TRACEPRINT(pProslic, "dataptr: %p\n", data);
+  for(address = PATCH_JMPTBL_START_ADDR;
+      address < (PATCH_JMPTBL_START_ADDR+(2*PATCH_NUM_LOW_ENTRIES)); address++)
+  {
+    if(*data)
+    {
+      regData = ReadReg(pProslic, pProslic->channel, address);
+      if(regData != ((*data) & 0xFF))
+      {
+        return FALSE;
+      }
+
+      address++;
+
+      regData = ReadReg(pProslic, pProslic->channel, address);
+      if(regData != (((*data)>>8) & 0xFF))
+      {
+        return FALSE;
+      }
+
+      data++;
+    }
+    else
+    {
+      break;
+    }
+  }
+  return TRUE;
+}
+
+#if defined SI3226X || defined SI3228X || defined SI3218X || defined SI3219X
+/* For chipsets supporting more than 8 jump entries, verify them */
+static BOOLEAN ProSLIC_VerifyPatchJMPHigh(proslicChanType *pProslic,
+    const uInt16 *data)
+{
+  uInt16 address = PATCH_JMPTBL_HIGH_ADDR;
+  ramData read_data;
+
+  TRACEPRINT(pProslic, "dataptr: %p\n", data);
+  for(address = PATCH_JMPTBL_HIGH_ADDR;
+      address < (PATCH_JMPTBL_HIGH_ADDR+PATCH_NUM_HIGH_ENTRIES); address++)
+  {
+    read_data = (ReadRAM(pProslic, pProslic->channel, address) & 0x1FFFL);
+    if(*data != read_data)
+    {
+      return FALSE;
+
+    }
+    data++;
+  }
+  return TRUE;
+}
+#endif /* SI3226X, SI3228X, SI3218X, SI3219X */
+
+static BOOLEAN ProSLIC_VerifyPatchSupportRAM(proslicChanType *pProslic, 
+                                           const uInt16 *ramAddr, const ramData *ramData)
+{
+  int i;
+
+  for(i = 0; ramAddr[i]; i++)
+  {
+    if( ReadRAM(pProslic, pProslic->channel, ramAddr[i]) != ramData[i])
+    {
+      return FALSE;
+    }
+  } 
+
+  return TRUE;
+}
+
+/* Load the first 8 jump table entries */
+static void ProSLIC_LoadPatchJMPLow(proslicChanType *pProslic, uInt8 channel,
+                                    const uInt16 *data)
+{
+  uInt8 address;
+
+  TRACEPRINT(pProslic, "chan: %d dataptr: %p\n", channel, data);
+
+  for(address = PATCH_JMPTBL_START_ADDR;
+      address < (PATCH_JMPTBL_START_ADDR+(2*PATCH_NUM_LOW_ENTRIES)); address++)
+  {
+    WriteReg(pProslic, channel, address,((*data) & 0xFF));
+    address++;
+    WriteReg(pProslic, channel, address,(((*data)>>8) & 0xFF));
+    data++;
+  }
+}
+
+/* Load Patch data */
+static void ProSLIC_LoadPatchData(proslicChanType *pProslic, uInt8 channel,
+                                  const ramData *data)
+{
+  int loop;
+
+  TRACEPRINT(pProslic, "chan: %d dataptr: %p\n", channel, data);
+  WriteRAM(pProslic, channel, PROSLIC_RAM_PRAM_ADDR, 0);
+
+  for(loop = 0; loop < PATCH_MAX_SIZE; loop++)
+  {
+    if(*data)
+    {
+      /* Can we take advantage of auto increment, if not, set the address */
+      if( (pProslic->deviceId->chipRev < 3)
+          && (channel == PROSLIC_CHAN_BROADCAST))
+      {
+        WriteRAM(pProslic, channel, PROSLIC_RAM_PRAM_ADDR, loop << 19);
+      }
+
+      WriteRAM(pProslic, channel, PROSLIC_RAM_PRAM_DATA, (*data) << 9);
+    }
+    else
+    {
+      return;
+    }
+    data++;
+  }
+}
+
+/* Load Support RAM - basically RAM address/data pairs to be written as part of the Patch process - do not call directly */
+void ProSLIC_LoadSupportRAM(proslicChanType *pProslic, uInt8 channel,
+                                   const uInt16 *address, const ramData *data)
+{
+  TRACEPRINT(pProslic, "chan: %d addressptr: %p dataptr: %p\n", channel, address,
+             data);
+  while( *address )
+  {
+    WriteRAM(pProslic, channel, *address, *data);
+    address++;
+    data++;
+  }
+}
+
+#if defined SI3226X || defined SI3228X || defined SI3218X || defined SI3219X
+/* Load Jump table high for chipsets supporting more than 8 jump entries */
+static void ProSLIC_LoadJMPHigh(proslicChanType *pProslic, uInt8 channel,
+                                const uInt16 *data)
+{
+  uInt16 loop;
+  TRACEPRINT(pProslic, "chan: %d dataptr: %p\n", channel, data);
+  for(loop = PATCH_JMPTBL_HIGH_ADDR;
+      loop < (PATCH_JMPTBL_HIGH_ADDR+PATCH_NUM_HIGH_ENTRIES); loop++)
+  {
+    WriteRAM(pProslic, channel, loop, ((*data) & 0x1FFFL) );
+    data++;
+  }
+}
+#endif /* SI3226X, SI3228X, SI3218X, SI3219X */
+
+/* Code assumes ProSLIC_LoadPatch has verified chip type. This is NOT meant to be called
+ * by the user directly.
+ */
+BOOLEAN ProSLIC_LoadPatch_extended(proslicChanType *pProslic,
+                                   const proslicPatch *pPatch, 
+                                   BOOLEAN is_broadcast, BOOLEAN is_second_chan)
+{
+  uInt8 channel;
+  const uInt16 jmp_disable[PATCH_NUM_LOW_ENTRIES] = {0,0,0,0,0,0,0,0};
+
+#if defined SI3226X || defined SI3228X || defined SI3218X ||defined SI3219X
+  BOOLEAN hasJmpTableHigh = FALSE;
+  const uInt16 jmphigh_disable[PATCH_NUM_HIGH_ENTRIES] = {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL};
+#endif
+
+  TRACEPRINT(pProslic, "patchptr: %p bcast: %d\n", pPatch, is_broadcast);
+
+  if(pPatch == NULL)
+  {
+    return RC_NONE;
+  }
+
+  if(is_broadcast == TRUE)
+  {
+    channel = PROSLIC_CHAN_BROADCAST;
+  }
+  else
+  {
+    channel = pProslic->channel;
+  }
+
+  ProSLIC_SetUserMode(pProslic,TRUE, is_broadcast);
+
+  /* Disable Patch */
+  WriteReg(pProslic, channel, PROSLIC_REG_JMPEN, 0);
+  if(is_second_chan == FALSE)
+  {
+    DEBUG_PRINT(pProslic, "%sloading patch: %08lx\n", LOGPRINT_PREFIX,
+                 (long unsigned int)pPatch->patchSerial);
+
+    ProSLIC_LoadPatchJMPLow(pProslic, channel, jmp_disable);
+
+#if defined SI3226X || defined SI3228X || defined SI3218X || defined SI3219X
+    if( 0
+#ifdef SI3226X
+        || (pProslic->deviceId->chipType >= SI32260
+            && pProslic->deviceId->chipType <= SI32269)
+#endif
+#ifdef SI3228X
+        || (pProslic->deviceId->chipType >= SI32280
+            && pProslic->deviceId->chipType <= SI32289)
+#endif
+#ifdef SI3218X
+        || (pProslic->deviceId->chipType >= SI32180
+            && pProslic->deviceId->chipType <= SI32189)
+#endif
+#ifdef SI3219X
+        || ( IS_SI3219X(pProslic->deviceId) )
+#endif
+      )
+    {
+      hasJmpTableHigh = TRUE;
+      ProSLIC_LoadJMPHigh(pProslic, channel, jmphigh_disable);
+    }
+#endif
+
+    ProSLIC_LoadPatchData(pProslic, channel, pPatch->patchData);
+
+    WriteReg(pProslic, channel, PROSLIC_REG_RAM_ADDR_HI, 0);
+
+    ProSLIC_LoadPatchJMPLow(pProslic, channel, pPatch->patchEntries);
+
+#if defined SI3226X || defined SI3228X || defined SI3218X || defined SI3219X
+    if(hasJmpTableHigh == TRUE)
+    {
+      ProSLIC_LoadJMPHigh(pProslic, channel,
+                          &(pPatch->patchEntries[PATCH_NUM_LOW_ENTRIES]));
+    }
+#endif
+    WriteRAM(pProslic, channel, PROSLIC_RAM_PATCHID,
+             pPatch->patchSerial); /* write the patch ID */
+  } /* !second channel */
+
+  ProSLIC_LoadSupportRAM(pProslic, channel, pPatch->psRamAddr, pPatch->psRamData);
+
+  return RC_NONE;
+
+}
+
+#endif /* patch helper functions */
+
+int ProSLIC_LoadPatch (proslicChanType_ptr pProslic,const proslicPatch *pPatch)
+{
+  int rc;
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  if( (rc = ProSLIC_LoadPatch_extended(pProslic, pPatch, FALSE, FALSE) ) == RC_NONE)
+  {
+#ifdef DISABLE_VERIFY_PATCH
+    return WriteReg(pProslic, pProslic->channel, PROSLIC_REG_JMPEN, 1);
+#endif
+  }
+
+  return rc;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_VerifyPatch (proslicChanType_ptr hProslic,const proslicPatch *pPatch)
+{
+  TRACEPRINT(hProslic, "patchptr: %p\n", pPatch);
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  if(pPatch == NULL)
+  {
+    return RC_NONE;
+  }
+
+  WriteReg(hProslic, hProslic->channel, PROSLIC_REG_JMPEN, 0);
+  WriteRAM(hProslic, hProslic->channel, PROSLIC_RAM_PRAM_ADDR, 0);
+
+  if(ProSLIC_VerifyPatchData(hProslic, pPatch->patchData,
+                             PATCH_MAX_SIZE) == FALSE)
+  {
+    DEBUG_PRINT(hProslic, "%sPatch data corrupted: channel %d\n",LOGPRINT_PREFIX,
+                hProslic->channel);
+    WriteRAM(hProslic, hProslic->channel, PROSLIC_RAM_PATCHID,
+             0UL); /* Mark patch as invalid */
+    return RC_PATCH_RAM_VERIFY_FAIL;
+  }
+
+  /*zero out RAM_ADDR_HI*/
+  WriteReg (hProslic, hProslic->channel, PROSLIC_REG_RAM_ADDR_HI,0);
+
+  if( ProSLIC_VerifyPatchJMPLow(hProslic, pPatch->patchEntries) == FALSE)
+  {
+    DEBUG_PRINT(hProslic,"%sPatch jumptable corrupted: channel %d\n",
+                LOGPRINT_PREFIX,hProslic->channel);
+    WriteRAM(hProslic, hProslic->channel, PROSLIC_RAM_PATCHID,
+             0UL); /* Mark patch as invalid */
+    return RC_PATCH_RAM_VERIFY_FAIL;
+  }
+
+#if defined SI3226X || defined SI3228X || defined SI3218X || defined SI3219X
+  if( 0
+#ifdef SI3226X
+      || (hProslic->deviceId->chipType >= SI32260
+          && hProslic->deviceId->chipType <= SI32269)
+#endif
+#ifdef SI3228X
+      || (hProslic->deviceId->chipType >= SI32280
+          && hProslic->deviceId->chipType <= SI32289)
+#endif
+#ifdef SI3218X
+      || (hProslic->deviceId->chipType >= SI32180
+          && hProslic->deviceId->chipType <= SI32189)
+#endif
+#ifdef SI3219X
+      || ( IS_SI3219X(hProslic->deviceId) )
+#endif
+    )
+
+  {
+    if( ProSLIC_VerifyPatchJMPHigh(hProslic,
+                                   &(pPatch->patchEntries[PATCH_NUM_LOW_ENTRIES])) == FALSE)
+    {
+      DEBUG_PRINT(hProslic,"%sPatch jumptable high corrupted: channel %d\n",
+                  LOGPRINT_PREFIX,hProslic->channel);
+      WriteRAM(hProslic, hProslic->channel, PROSLIC_RAM_PATCHID,
+               0UL); /* Mark patch as invalid */
+      return RC_PATCH_ENTRY_VERIFY_FAIL;
+    }
+  }
+
+#endif
+
+  if( ProSLIC_VerifyPatchSupportRAM( hProslic, pPatch->psRamAddr, pPatch->psRamData) == FALSE)
+  {
+      DEBUG_PRINT(hProslic,"%sPatch init data corrupted: channel %d\n",
+                  LOGPRINT_PREFIX,hProslic->channel);
+      WriteRAM(hProslic, hProslic->channel, PROSLIC_RAM_PATCHID,
+               0UL); /* Mark patch as invalid */
+      return RC_PATCH_ENTRY_VERIFY_FAIL;
+  }
+
+  WriteReg (hProslic, hProslic->channel, PROSLIC_REG_JMPEN,
+            1); /*enable the patch*/
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_SetMuteStatus (proslicChanType_ptr pProslic,
+                           ProslicMuteModes muteEn)
+{
+
+  uInt8 regTemp;
+  uInt8 newRegValue;
+  TRACEPRINT(pProslic, "muteEn: %d\n", muteEn);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  regTemp = ReadReg (pProslic,pProslic->channel,PROSLIC_REG_DIGCON);
+
+  WriteReg (pProslic,pProslic->channel,PROSLIC_REG_DIGCON,regTemp&~(0x3));
+  newRegValue = regTemp &~(0x3);
+
+  if (muteEn & PROSLIC_MUTE_RX)
+  {
+    newRegValue |= 1;
+  }
+
+  if (muteEn & PROSLIC_MUTE_TX)
+  {
+    newRegValue |= 2;
+  }
+
+  if(newRegValue != regTemp)
+  {
+    return WriteReg (pProslic,pProslic->channel,PROSLIC_REG_DIGCON,newRegValue);
+  }
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_SetLoopbackMode (proslicChanType_ptr pProslic,
+                             ProslicLoopbackModes newMode)
+{
+  uInt8 regTemp, newValue;
+  TRACEPRINT(pProslic, "mode: %d\n", newMode);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  newValue = regTemp = ReadReg (pProslic,pProslic->channel,PROSLIC_REG_LOOPBACK);
+
+  switch (newMode)
+  {
+    case PROSLIC_LOOPBACK_NONE:
+      newValue &= ~(0x11);
+      break;
+
+    case PROSLIC_LOOPBACK_DIG:
+      newValue |= 1;
+      break;
+
+    case PROSLIC_LOOPBACK_ANA:
+      newValue |= 0x10;
+      break;
+  }
+
+  if(newValue != regTemp)
+  {
+    return WriteReg (pProslic,pProslic->channel,PROSLIC_REG_LOOPBACK, newValue);
+  }
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_EnableInterrupts (proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_EnableInterrupts(hProslic);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_EnableInterrupts(hProslic);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_EnableInterrupts(hProslic);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_EnableInterrupts(hProslic);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_EnableInterrupts(hProslic);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+
+/*****************************************************************************************************/
+int ProSLIC_DisableInterrupts (proslicChanType_ptr hProslic)
+{
+#ifdef GCI_MODE
+  uInt8 data;
+#endif
+  uInt8 i;
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  for(i = PROSLIC_REG_IRQEN1; i < PROSLIC_REG_IRQEN4; i++)
+  {
+    /* Disable the interrupts */
+    WriteReg(hProslic, hProslic->channel, i, 0);
+  }
+
+  /* Clear the pending interrupts */
+  for(i = PROSLIC_REG_IRQ1; i < PROSLIC_REG_IRQ4; i++)
+  {
+#ifdef GCI_MODE
+    data = ReadReg(hProslic, hProslic->channel, i);
+    WriteReg( hProslic, hProslic->channel, i, data);
+#else
+    (void)ReadReg(hProslic, hProslic->channel, i);
+#endif
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_RingSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+#ifndef DISABLE_RING_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_RingSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_RingSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_RingSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_RingSetup(hProslic,preset);
+  }
+#endif
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_RingSetup(hProslic,preset);
+  }
+#endif
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_RING_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_ToneGenSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+#ifndef DISABLE_TONE_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return ProSLIC_ToneGenSetupPtr(hProslic,&(Si3217x_Tone_Presets[preset]));
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return ProSLIC_ToneGenSetupPtr(hProslic, &(Si3218x_Tone_Presets[preset]));
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return ProSLIC_ToneGenSetupPtr(hProslic, &(Si3219x_Tone_Presets[preset]));
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return ProSLIC_ToneGenSetupPtr(hProslic, &(Si3226x_Tone_Presets[preset]));
+  }
+#endif
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return ProSLIC_ToneGenSetupPtr(hProslic, &(Si3228x_Tone_Presets[preset]));
+  }
+#endif
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_TONE_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_FSKSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+#ifndef DISABLE_FSK_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return ProSLIC_FSKSetupPtr(hProslic, &Si3217x_FSK_Presets[preset]);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return ProSLIC_FSKSetupPtr(hProslic, &Si3218x_FSK_Presets[preset]);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return ProSLIC_FSKSetupPtr(hProslic, &Si3219x_FSK_Presets[preset]);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return ProSLIC_FSKSetupPtr(hProslic, &Si3226x_FSK_Presets[preset]);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return ProSLIC_FSKSetupPtr(hProslic,&Si3228x_FSK_Presets[preset]);
+  }
+#endif
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_FSK_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_ZsynthSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+#ifndef DISABLE_ZSYNTH_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_ZsynthSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_ZsynthSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_ZsynthSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_ZsynthSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_ZsynthSetup(hProslic,preset);
+  }
+#endif
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_ZSYNTH_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+#ifndef DISABLE_CI_SETUP
+int ProSLIC_GciCISetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_GciCISetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_GciCISetup(hProslic,preset);
+  }
+#endif
+
+#if !defined(SI3217X) && !defined(SI3226X)
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+#endif /*DISABLE_CI_SETUP*/
+
+/*****************************************************************************************************/
+int ProSLIC_TXAudioGainSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+#ifndef DISABLE_AUDIOGAIN_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_TXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_TXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_TXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_TXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_TXAudioGainSetup(hProslic,preset);
+  }
+#endif
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+
+#endif /*DISABLE_AUDIOGAIN_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_RXAudioGainSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+#ifndef DISABLE_AUDIOGAIN_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_RXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_RXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_RXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_RXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_RXAudioGainSetup(hProslic,preset);
+  }
+#endif
+
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_AUDIOGAIN_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_TXAudioGainScale (proslicChanType_ptr hProslic,int preset,
+                              uInt32 pga_scale, uInt32 eq_scale)
+{
+  TRACEPRINT(hProslic, "preset: %d pga_scale: %u eq_scale: %u\n", preset,
+             pga_scale, eq_scale);
+#ifndef DISABLE_AUDIOGAIN_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_TXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_TXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_TXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_TXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_TXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_AUDIOGAIN_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_RXAudioGainScale (proslicChanType_ptr hProslic,int preset,
+                              uInt32 pga_scale, uInt32 eq_scale)
+{
+  TRACEPRINT(hProslic, "preset: %d pga_scale: %u eq_scale: %u\n", preset,
+             pga_scale, eq_scale);
+#ifndef DISABLE_AUDIOGAIN_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_RXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_RXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_RXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_RXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_RXAudioGainScale(hProslic,preset,pga_scale,eq_scale);
+  }
+#endif
+
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_AUDIOGAIN_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_AudioGainSetup (proslicChanType_ptr pProslic,int32 rxgain,
+                            int32 txgain,int preset)
+{
+  int rc;
+#ifndef DISABLE_AUDIOGAIN_SETUP
+  int atx_preset = TXACGAIN_SEL;
+  int arx_preset = RXACGAIN_SEL;
+  TRACEPRINT(pProslic, "rxgain: %d txgain: %d preset: %d\n", rxgain, txgain,
+             preset);
+
+  rc = ProSLIC_dbgSetTXGain(pProslic,txgain,preset,atx_preset);
+
+  if( rc  == RC_NONE)
+  {
+    rc = ProSLIC_TXAudioGainSetup(pProslic,TXACGAIN_SEL);
+  }
+
+  if( rc  == RC_NONE)
+  {
+    rc = ProSLIC_dbgSetRXGain(pProslic,rxgain,preset,arx_preset);
+  }
+
+  if( rc  == RC_NONE)
+  {
+    rc = ProSLIC_RXAudioGainSetup(pProslic,RXACGAIN_SEL);
+  }
+  return rc;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+  return RC_IGNORE;
+#endif /*DISABLE_AUDIOGAIN_SETUP*/
+}
+
+/*****************************************************************************************************/
+int ProSLIC_DCFeedSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset: %d\n", preset);
+#ifndef DISABLE_DCFEED_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_DCFeedSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_DCFeedSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_DCFeedSetupCfg(hProslic, Si3219x_DCfeed_Presets, preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_DCFeedSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_DCFeedSetup(hProslic,preset);
+  }
+#endif
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_DCFEED_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_DCFeedSetupCfg (proslicChanType_ptr hProslic,
+                            ProSLIC_DCfeed_Cfg *cfg, int preset)
+{
+  TRACEPRINT(hProslic, "cfgPtr = %p preset = %d\n", cfg, preset);
+#ifndef DISABLE_DCFEED_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_DCFeedSetupCfg(hProslic,cfg,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_DCFeedSetupCfg(hProslic,cfg,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_DCFeedSetupCfg(hProslic,cfg,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_DCFeedSetupCfg(hProslic,cfg,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_DCFeedSetupCfg(hProslic,cfg,preset);
+  }
+#endif
+
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+  SILABS_UNREFERENCED_PARAMETER(cfg);
+#endif /*DISABLE_DCFEED_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_GPIOSetup (proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+#ifndef DISABLE_GPIO_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_GPIOSetup(hProslic);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_GPIOSetup(hProslic);
+  }
+#endif
+
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+#endif /*DISABLE_GPIO_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+#ifndef DISABLE_PULSEMETERING
+int ProSLIC_PulseMeterSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset = %d\n", preset);
+#ifndef DISABLE_PULSE_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_PulseMeterSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_PulseMeterSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_PulseMeterSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_PulseMeterSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_PulseMeterSetup(hProslic,preset);
+  }
+#endif
+
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_PULSE_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+int ProSLIC_PCMSetup (proslicChanType_ptr hProslic,int preset)
+{
+  TRACEPRINT(hProslic, "preset = %d\n", preset);
+#ifndef DISABLE_PCM_SETUP
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_PCMSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_PCMSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_PCMSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_PCMSetup(hProslic,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_PCMSetup(hProslic,preset);
+  }
+#endif
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  SILABS_UNREFERENCED_PARAMETER(preset);
+#endif /*DISABLE_PCM_SETUP*/
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PCMTimeSlotSetup (proslicChanType_ptr pProslic, uInt16 rxcount,
+                              uInt16 txcount)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "rx = %u tx = %u\n", rxcount, txcount);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  data = txcount & 0xff;
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_PCMTXLO,data);
+
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_PCMTXHI);
+  data &= 0x10;  /* keep TX_EDGE bit */
+  data |= ((txcount >> 8)&0x03) ;
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_PCMTXHI,data);
+
+  data = rxcount & 0xff;
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_PCMRXLO,data);
+
+  data = (rxcount >> 8) & 0x3; /* PCMRXHI has only 2 bits for timeslot */
+  /* add to the calculated timeslot values the non timeslot bits */
+  data |= (ReadReg(pProslic,pProslic->channel,PROSLIC_REG_PCMRXHI) & 0xFC);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_PCMRXHI,data);
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+typedef ProslicInt proslicIntTypeMap[SI_MAX_INTERRUPTS][8];
+
+static int ProSLIC_ReadInterruptsHelper(proslicChanType_ptr pProslic,
+                                        uInt8 *regData, uInt8 numChannels)
+{
+  uInt8 i;
+  uInt8 intsActive;
+  uInt8 *currentData = regData;
+  SILABS_UNREFERENCED_PARAMETER(numChannels);
+
+  intsActive = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_IRQ0);
+
+#ifdef PROSLIC_OPTIMIZE_INTERRUPTS
+  /* For dual channel devices, we need to shift the upper nibble for the second channel
+     if the caller requested the second channel.  We determine this by channel ID being
+     even or odd.  If this is NOT true - for example a Si3217x and then a Si3226x chipset
+     configuration on the same daisychain, then this optimization logic will not work */
+#if defined(SI3226X) || defined(SI3228X)
+  if( (numChannels != 0) && ((pProslic->channel) & 0x1))
+  {
+    intsActive = intsActive >> 4;
+  }
+#endif /* Multichannel devices */
+#endif
+
+  /* If there are no interrupts, stop... return back to calling function */
+  if((intsActive &0xF) == 0)
+  {
+    return RC_IGNORE;
+  }
+
+  for(i = PROSLIC_REG_IRQ1; i <= PROSLIC_REG_IRQ4; i++)
+  {
+#ifdef PROSLIC_OPTIMIZE_INTERRUPTS
+    /* Read IRQn Register only if IRQ0 states there was an interrupt pending, otherwise
+       skip it. This eliminates unneeded SPI transactions.
+    */
+    if( (intsActive & (1<<(i-PROSLIC_REG_IRQ1))) == 0)
+    {
+      *currentData++ = 0;
+      continue;
+    }
+#endif
+    *currentData = (uInt8)ReadReg(pProslic, pProslic->channel, i);
+#ifdef GCI_MODDE
+    WriteReg(pProslic, pProslic->channel, i, *current_data);
+#endif
+    currentData++;
+  } /* for loop */
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*
+ Reads IRQ0 to determine if an interrupt has occurred for the particular device,
+ if so, reads the interrupt register(s) that fired the interrupt and then
+ maps the interrupt(s) to the generic interrupt value to return to the caller.
+
+ Code assumes normal chipset/compatibility testing has already been done.
+*/
+static int ProSLIC_GetInterruptHelper(proslicChanType_ptr pProslic,
+                                      const proslicIntTypeMap intMap, proslicIntType *pIntData, uInt8 numChannels)
+{
+  int i,j;
+  uInt8 intData[SI_MAX_INTERRUPTS];
+  uInt8 *currentData;
+  uInt8 map, intCount;
+  BOOLEAN safetyInt = FALSE;
+
+  /* Initialize interrupt count to 0 */
+  pIntData-> number = 0;
+
+  if( ProSLIC_ReadInterruptsHelper(pProslic, intData, numChannels) == RC_IGNORE)
+  {
+    /* No interrupts for the given channel. */
+    return RC_NONE;
+  }
+
+  /* At this point we've collected all the registers, now decode the data */
+  currentData = intData;
+  intCount = 0;
+
+  for(i = 0; i < SI_MAX_INTERRUPTS; i++)
+  {
+    if(*currentData)
+    {
+      for(j = 0; j < 8; j++)
+      {
+        if( *currentData & (1<<j) )
+        {
+          map = intMap[i][j];
+          pIntData->irqs[intCount] = map;
+
+          if( (map == IRQ_P_HVIC)
+              || (map == IRQ_P_THERM) )
+          {
+            safetyInt = TRUE;
+          }
+
+          intCount++;
+        }
+      }
+    }
+    currentData++;
+  }
+  
+  pIntData->number = intCount;
+  
+  if( safetyInt == TRUE)
+  {
+    if(ProSLIC_isReinitRequired(pProslic))
+    {
+      return RC_REINIT_REQUIRED;
+    }
+  }
+
+  return pIntData->number;
+}
+
+
+int ProSLIC_GetInterrupts (proslicChanType_ptr hProslic,
+                           proslicIntType *pIntData)
+{
+  const proslicIntTypeMap interruptMap =
+  {
+    {IRQ_OSC1_T1, IRQ_OSC1_T2, IRQ_OSC2_T1, IRQ_OSC2_T2, IRQ_RING_T1, IRQ_RING_T2, IRQ_FSKBUF_AVAIL, IRQ_VBAT},
+    {IRQ_RING_TRIP, IRQ_LOOP_STATUS, IRQ_LONG_STAT, IRQ_VOC_TRACK, IRQ_DTMF, IRQ_INDIRECT, IRQ_RXMDM, IRQ_TXMDM},
+    {IRQ_P_HVIC, IRQ_P_THERM, IRQ_PQ3, IRQ_PQ4, IRQ_PQ5, IRQ_PQ6, IRQ_DSP, IRQ_MADC_FS},
+    {IRQ_USER_0, IRQ_USER_1, IRQ_USER_2, IRQ_USER_3, IRQ_USER_4, IRQ_USER_5, IRQ_USER_6, IRQ_USER_7}
+  };
+
+  pIntData->number=0;
+  /* TRACEPRINT(hProslic, "\n", NULL); */
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#if defined (SI3217X) || defined (SI3218X) || defined(SI3219X)
+  if (0
+#ifdef SI3217X
+      || (hProslic->deviceId->chipType >= SI32171
+          && hProslic->deviceId->chipType <= SI32179)
+#endif
+#ifdef SI3218X
+      || (hProslic->deviceId->chipType >= SI32180
+          && hProslic->deviceId->chipType <= SI32189)
+#endif
+#ifdef SI3219X
+      || ( IS_SI3219X(hProslic->deviceId) )
+#endif
+     )
+  {
+    return ProSLIC_GetInterruptHelper(hProslic, interruptMap, pIntData, 1);
+  }
+#endif
+#if defined (SI3226X) || defined (SI3228X)
+  if( 0
+#ifdef SI3226X
+      || (hProslic->deviceId->chipType >= SI32260
+          && hProslic->deviceId->chipType <= SI32269)
+#endif
+#ifdef SI3228X
+      || (hProslic->deviceId->chipType >= SI32280
+          && hProslic->deviceId->chipType <= SI32289)
+#endif
+    )
+  {
+    return ProSLIC_GetInterruptHelper(hProslic, interruptMap, pIntData, 2);
+  }
+#endif
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_ReadHookStatus (proslicChanType_ptr pProslic,uInt8 *pHookStat)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+  *pHookStat = PROSLIC_ONHOOK;
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  if (ReadReg(pProslic,pProslic->channel,PROSLIC_REG_LCRRTP) & 2)
+  {
+    *pHookStat=PROSLIC_OFFHOOK;
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_SetLinefeedStatus (proslicChanType_ptr pProslic, uInt8 newLinefeed)
+{
+  uInt8 lfState;
+  uInt8 irqen1=0;
+  TRACEPRINT(pProslic, "linefeed = %u\n", newLinefeed);
+  
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  /* Get the irqen1 setting - used to determine if vbat interrupt was set... */
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+    && pProslic->deviceId->chipType <= SI32179)
+  {
+      irqen1 = Si3217x_General_Configuration.irqen1;
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+    && pProslic->deviceId->chipType <= SI32189)
+  {
+      irqen1 = Si3218x_General_Configuration.irqen1;
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+      irqen1 = Si3219x_General_Configuration.irqen1;
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+    && pProslic->deviceId->chipType <= SI32269)
+  {
+      irqen1 = Si3226x_General_Configuration.irqen1;
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+    && pProslic->deviceId->chipType <= SI32289)
+  {
+      irqen1 = Si3228x_General_Configuration.irqen1;
+  }
+#endif
+
+  if( (newLinefeed& 0xF)  == LF_RINGING )
+  {
+    uInt8 regTemp;
+
+    lfState = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_LINEFEED);
+
+    /* Only change to ringing state if not ringing... */
+    if( (lfState & 0xF) != LF_RINGING )
+    {
+      if(irqen1 & 0x80)
+      {
+        /*disable vbat interrupt during ringing*/
+        regTemp = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_IRQEN1 );
+        WriteReg (pProslic, pProslic->channel, PROSLIC_REG_IRQEN1, regTemp&(~0x80));
+      }
+
+      WriteReg(pProslic, pProslic->channel, PROSLIC_REG_LINEFEED, LF_RINGING);
+    }
+    else
+    {
+      return RC_IGNORE;
+    }
+  }
+  else
+  {
+    uInt8 autord;
+
+    /* Preserve the auto register so we can restore it at the end */
+    autord = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_AUTORD );
+    WriteReg(pProslic, pProslic->channel, PROSLIC_REG_AUTORD, (autord & 0xFB) ); /* Disable AutoRD */
+
+    lfState = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_LINEFEED);
+
+    if( (lfState & 0xF) == LF_RINGING ) 
+    {
+      WriteReg(pProslic, pProslic->channel, PROSLIC_REG_LINEFEED, newLinefeed);
+    }
+    else
+    {
+      /* We are already doing a state transition, abort request */
+      if( ((lfState & 0xF0) == (LF_RINGING << 4) )
+        && ( (lfState & 0xF) != LF_RINGING) )
+      {
+        WriteReg(pProslic, pProslic->channel, PROSLIC_REG_AUTORD, autord ); /* restore the autord bit */
+        return RC_IGNORE;
+      }
+
+      WriteReg(pProslic, pProslic->channel, PROSLIC_REG_LINEFEED, newLinefeed);
+    }
+    /* Restore autord */
+    WriteReg(pProslic, pProslic->channel, PROSLIC_REG_AUTORD, autord );
+
+    /* Restore IRQEN1 to what the user specified - if we changed it.. */
+    if(irqen1 & 0x80)
+    {
+      WriteReg (pProslic, pProslic->channel, PROSLIC_REG_IRQEN1, irqen1);
+    }
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_SetLinefeedStatusBroadcast (proslicChanType_ptr hProslic,
+                                        uInt8 newLinefeed)
+{
+  TRACEPRINT(hProslic, "linefeed = %u\n", newLinefeed);
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  WriteReg(hProslic, PROSLIC_CHAN_BROADCAST, PROSLIC_REG_LINEFEED, newLinefeed);
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PolRev (proslicChanType_ptr pProslic,uInt8 abrupt,
+                    uInt8 newPolRevState)
+{
+  uInt8 data = 0;
+  TRACEPRINT(pProslic, "abrupt = %u newPolRevState = %u\n", abrupt,
+             newPolRevState);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  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;
+  }
+
+  /* Cannot polrev/wink while low power mode is active */
+  ProSLIC_SetPowersaveMode(pProslic,PWRSAVE_DISABLE);
+
+  if (abrupt)
+  {
+    data |= 1;
+  }
+
+  WriteReg(pProslic, pProslic->channel, PROSLIC_REG_POLREV,data);
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_GPIOControl (proslicChanType_ptr pProslic,uInt8 *pGpioData,
+                         uInt8 read)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#if defined(SI3217X) || defined (SI3226X)
+  if( 0
+#ifdef SI3217X
+      || (pProslic->deviceId->chipType >= SI32171
+          && pProslic->deviceId->chipType <= SI32179)
+#endif
+#ifdef SI3226X
+      || (pProslic->deviceId->chipType >= SI32260
+          && pProslic->deviceId->chipType <= SI32269)
+#endif
+    )
+  {
+    if (read)
+    {
+      *pGpioData = 0xf & ReadReg(pProslic,pProslic->channel,PROSLIC_REG_GPIO);
+    }
+    else
+    {
+      WriteReg(pProslic,pProslic->channel,PROSLIC_REG_GPIO,
+               (*pGpioData)|(ReadReg(pProslic,pProslic->channel,PROSLIC_REG_GPIO)&0xf0));
+    }
+    return RC_NONE;
+  }
+#else
+  SILABS_UNREFERENCED_PARAMETER(read);
+  SILABS_UNREFERENCED_PARAMETER(pGpioData);
+#endif 
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+/*
+** Optional Neon Message Waiting Support
+*/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_MWISetV (proslicChanType_ptr hProslic, uInt16 vpk_mag)
+{
+  uInt32 ram_val;
+  uInt8 max;
+  
+  TRACEPRINT(hProslic, "vpk_mag = %u\n", vpk_mag);
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  
+  /* Set the maximum MWI voltage according to the chipset */
+#if defined (SI3217X) || defined (SI3226X)
+  if( 0
+#ifdef SI3217X
+      || (hProslic->deviceId->chipType >= SI32171
+          && hProslic->deviceId->chipType <= SI32179)
+#endif
+#ifdef SI3226X
+      || (hProslic->deviceId->chipType >= SI32260
+          && hProslic->deviceId->chipType <= SI32269)
+#endif
+    )
+  {
+    max = SIL_MWI_VPK_MAX;
+  }
+#endif /*17x/26x */
+
+#if defined (SI3218X) || defined (SI3228X) || defined(SI3219X)
+  if( 0
+#ifdef SI3218X
+    || (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+#endif
+
+#ifdef SI3228X
+    || (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+#endif
+
+#ifdef SI3219X
+    || IS_SI3219X(hProslic->deviceId) 
+#endif
+
+#ifdef SI3228X
+      || (hProslic->deviceId->chipType >= SI32280
+          && hProslic->deviceId->chipType <= SI32289)
+#endif
+    )
+  {
+    max = SIL_MWI_VPK_MAX_LO;
+  }
+#endif /* 18x, 28x, 19x */
+
+  /* Voltage mod */
+  if(vpk_mag > 0)  /* Skip if 0 passed */
+  {
+    /* Clamp supplied value to allowable range */
+    if(vpk_mag > max)
+    {
+      vpk_mag = max;
+    }
+    if(vpk_mag < SIL_MWI_VPK_MIN)
+    {
+      vpk_mag = SIL_MWI_VPK_MIN;
+    }
+    ram_val = vpk_mag * SCALE_R_MADC * 1000L;
+    WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_MWI_V,ram_val);
+  }
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_MWIEnable (proslicChanType_ptr hProslic)
+{
+  uInt8 val;
+  ramData ram_val;
+  
+  TRACEPRINT(hProslic, "\n", NULL);
+  
+  /*
+  ** Check for conditions that would prevent enabling MWI
+  */
+  ProSLIC_ReadHookStatus(hProslic,&val);
+  if(val != PROSLIC_ONHOOK)
+  {
+    return RC_MWI_ENABLE_FAIL;
+  }
+  
+  val = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_USERSTAT);
+
+  /* Check if PROSLIC and disabled MWI, if not, ignore this request. */
+  if( (hProslic->channelType != PROSLIC)
+       || (val & SIL_MWI_USTAT_SET ) )
+  {
+    return RC_IGNORE;
+  }
+  
+  /* Save parameters */
+  hProslic->mwiSave.ringof = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGOF);
+  hProslic->mwiSave.ringamp = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGAMP);
+  hProslic->mwiSave.vbatr_expect = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_VBATR_EXPECT);
+  hProslic->mwiSave.vov_ring_bat = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_VOV_RING_BAT);
+  hProslic->mwiSave.vov_ring_gnd = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_VOV_RING_GND);
+  hProslic->mwiSave.rtacth = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTACTH);
+  hProslic->mwiSave.rtdcth = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTDCTH);
+  hProslic->mwiSave.iring_lim = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_IRING_LIM);
+  hProslic->mwiSave.dcdc_rngtype = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_DCDC_RNGTYPE);
+  hProslic->mwiSave.slope_ring = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_SLOPE_RING);
+  hProslic->mwiSave.rtper = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTPER);
+  hProslic->mwiSave.ringfr = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGFR);
+  hProslic->mwiSave.rtdcdb = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTDCDB);
+  hProslic->mwiSave.lcrmask = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_LCRMASK);
+  hProslic->mwiSave.dcdc_oithresh_lo = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_DCDC_OITHRESH_LO);
+  hProslic->mwiSave.enhance = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE);
+  hProslic->mwiSave.ringcon = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_RINGCON);
+  hProslic->mwiSave.userstat =  val;
+  hProslic->mwiSave.linefeed = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_LINEFEED);
+  
+  /* Modify parameters */
+  ProSLIC_SetLinefeedStatus(hProslic,LF_FWD_ACTIVE);
+  ram_val = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_MWI_V);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGOF,ram_val);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGAMP,0x0L);
+
+  /* Set the VBATR_EXPECT according to the chipset */
+#if defined (SI3217X) || defined (SI3226X)
+  if( 0
+#ifdef SI3217X
+      || (hProslic->deviceId->chipType >= SI32171
+          && hProslic->deviceId->chipType <= SI32179)
+#endif
+#ifdef SI3226X
+      || (hProslic->deviceId->chipType >= SI32260
+          && hProslic->deviceId->chipType <= SI32269)
+#endif
+    )
+  {
+    ram_val = 0x7FFFFC2L;
+  }
+#endif
+
+#if defined (SI3218X) || defined (SI3228X) || defined(SI3219X)
+  if( 0
+#ifdef SI3218X
+      || (hProslic->deviceId->chipType >= SI32180
+          && hProslic->deviceId->chipType <= SI32189)
+#endif
+
+#ifdef SI3228X
+      || (hProslic->deviceId->chipType >= SI32280
+          && hProslic->deviceId->chipType <= SI32289)
+#endif
+
+#ifdef SI3219X
+    || IS_SI3219X(hProslic->deviceId) 
+#endif
+    )
+  {
+    ram_val = 0x06866635L;
+  }
+#endif /* 18x,28x, 19x */
+
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_VBATR_EXPECT,ram_val);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_VOV_RING_BAT,0x0L);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_VOV_RING_GND,0x051EB80L);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTACTH,0x0FFFFFFFL);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTDCTH,0x38E38EL);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_IRING_LIM,0x380000L);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_DCDC_RNGTYPE,0x100000L);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_SLOPE_RING,0x15E5200EL);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTPER,0x50000L);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGFR,0x07EFE000L);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTDCDB,0x0000A000L);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_LCRMASK,0x000F0000L);
+  ram_val = ReadRAM(hProslic,hProslic->channel,PROSLIC_RAM_DCDC_OITHRESH_HI);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_DCDC_OITHRESH_LO,ram_val);
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE,hProslic->mwiSave.enhance&0xEF);
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_RINGCON,0x00);
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_USERSTAT,0x0C);
+  
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_MWIDisable (proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  /* Check if PROSLIC and enabled MWI, if not, ignore this request. */
+  if( (hProslic->channelType != PROSLIC)
+       || !(ReadReg(hProslic,hProslic->channel,PROSLIC_REG_USERSTAT) & SIL_MWI_USTAT_SET ) )
+  {
+    return RC_IGNORE;
+  }
+
+  ProSLIC_SetLinefeedStatus(hProslic,LF_FWD_ACTIVE);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGOF,hProslic->mwiSave.ringof);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGAMP,hProslic->mwiSave.ringamp);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_VBATR_EXPECT,hProslic->mwiSave.vbatr_expect);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_VOV_RING_BAT,hProslic->mwiSave.vov_ring_bat);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_VOV_RING_GND,hProslic->mwiSave.vov_ring_gnd);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTACTH,hProslic->mwiSave.rtacth);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTDCTH,hProslic->mwiSave.rtdcth);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_IRING_LIM,hProslic->mwiSave.iring_lim);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_DCDC_RNGTYPE,hProslic->mwiSave.dcdc_rngtype);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_SLOPE_RING,hProslic->mwiSave.slope_ring);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTPER,hProslic->mwiSave.rtper);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RINGFR,hProslic->mwiSave.ringfr);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_RTDCDB,hProslic->mwiSave.rtdcdb);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_LCRMASK,hProslic->mwiSave.lcrmask);
+  WriteRAM(hProslic,hProslic->channel,PROSLIC_RAM_DCDC_OITHRESH_LO,hProslic->mwiSave.dcdc_oithresh_lo);
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE,hProslic->mwiSave.enhance);
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_RINGCON,hProslic->mwiSave.ringcon);
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_USERSTAT,hProslic->mwiSave.userstat);
+  ProSLIC_SetLinefeedStatus(hProslic,hProslic->mwiSave.linefeed);
+  
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_SetMWIState (proslicChanType_ptr hProslic,uInt8 flash_on)
+{
+  TRACEPRINT(hProslic, "flash_on = %u\n", flash_on);
+  /* Check if PROSLIC and enabled MWI, if not, ignore this request. */
+  if( (hProslic->channelType != PROSLIC)
+       || !(ReadReg(hProslic,hProslic->channel,PROSLIC_REG_USERSTAT) & SIL_MWI_USTAT_SET ) )
+  {
+    return RC_IGNORE;
+  }
+  
+  if(flash_on)
+  {
+    ProSLIC_SetLinefeedStatus(hProslic,LF_RINGING);
+  }
+  else
+  {
+    ProSLIC_SetLinefeedStatus(hProslic,LF_FWD_ACTIVE);
+  }
+  
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_GetMWIState (proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+  /* Check if PROSLIC and enabled MWI, if not, ignore this request. */
+  if( (hProslic->channelType != PROSLIC)
+       || !(ReadReg(hProslic,hProslic->channel,PROSLIC_REG_USERSTAT) & SIL_MWI_USTAT_SET ) )
+  {
+    return RC_IGNORE;
+  }
+  
+  if(ReadReg(hProslic,hProslic->channel,PROSLIC_REG_LINEFEED) == 0x44)
+  {
+    return SIL_MWI_FLASH_ON;
+  }
+  else
+  {
+    return SIL_MWI_FLASH_OFF;
+  }
+  
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/******************************************************************************/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_MWIRampPoll(proslicChanType_ptr pProslic)
+{
+  uInt32 mwi_voltage;
+  
+  /* Check if PROSLIC and enabled MWI, if not, ignore this request. */
+  if( (pProslic->channelType != PROSLIC)
+       || !(ReadReg(pProslic,pProslic->channel,PROSLIC_REG_USERSTAT) & SIL_MWI_USTAT_SET ) )
+  {
+    return RC_IGNORE;
+  }
+  
+  switch(pProslic->mwiState.state)
+  {
+    case PROSLIC_MWI_RAMP_ON:
+    {
+      if(pProslic->mwiState.ticks == pProslic->mwiState.poll.steps)
+      {
+        mwi_voltage = pProslic->mwiState.poll.voff + pProslic->mwiState.poll.step_size;
+        WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_RINGOF,mwi_voltage);
+        ProSLIC_SetLinefeedStatus(pProslic,LF_RINGING);
+      }
+      else if(pProslic->mwiState.ticks == 0)
+      {
+        mwi_voltage = pProslic->mwiState.poll.von;
+        WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_RINGOF,mwi_voltage);
+        pProslic->mwiState.ticks = pProslic->mwiState.poll.onTime+1;
+        pProslic->mwiState.state = PROSLIC_MWI_ON;
+      }
+      else
+      {
+        mwi_voltage = pProslic->mwiState.poll.voff + pProslic->mwiState.poll.step_size*(pProslic->mwiState.poll.steps - pProslic->mwiState.ticks + 1);
+        WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_RINGOF,mwi_voltage);
+      }
+    }
+    break;
+
+    case PROSLIC_MWI_RAMP_OFF:
+    {
+      if(pProslic->mwiState.ticks == 0)
+      {
+        pProslic->mwiState.ticks = pProslic->mwiState.poll.offTime+1;
+        pProslic->mwiState.state = PROSLIC_MWI_OFF;
+        ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);
+        }
+      else 
+      {
+        mwi_voltage = pProslic->mwiState.poll.von - (pProslic->mwiState.poll.steps - pProslic->mwiState.ticks + 1)*pProslic->mwiState.poll.step_size;
+        WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_RINGOF,mwi_voltage);
+      }
+    break;
+    }
+    
+    case PROSLIC_MWI_ON:
+      if(pProslic->mwiState.ticks == 0)
+      {
+        pProslic->mwiState.ticks = pProslic->mwiState.poll.steps+1;
+        pProslic->mwiState.state = PROSLIC_MWI_RAMP_OFF;
+      }
+      break;
+      
+    case PROSLIC_MWI_OFF:
+      if(pProslic->mwiState.ticks == 0)
+      {
+        pProslic->mwiState.ticks = pProslic->mwiState.poll.steps+1;
+        pProslic->mwiState.state = PROSLIC_MWI_RAMP_ON;
+      }
+      break;
+
+    default:
+      /* Do nothing */
+      break;
+  }
+  (pProslic->mwiState.ticks)--; 
+
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/******************************************************************************/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_MWIRampStart(proslicChanType_ptr pProslic, uInt32 steps, uInt32 onTime, uInt32 offTime)
+{
+  /* Check if PROSLIC and enabled MWI, if not, ignore this request. */
+  if( (pProslic->channelType != PROSLIC)
+       || !(ReadReg(pProslic,pProslic->channel,PROSLIC_REG_USERSTAT) & SIL_MWI_USTAT_SET ) )
+  {
+    return RC_IGNORE;
+  }
+  
+  pProslic->mwiState.poll.steps = steps-1;
+  pProslic->mwiState.poll.onTime = onTime;
+  pProslic->mwiState.poll.offTime = offTime;
+  
+  pProslic->mwiState.poll.von = ReadRAM(pProslic,pProslic->channel,PROSLIC_RAM_MWI_V);
+  pProslic->mwiState.poll.voff = (ReadRAM(pProslic,pProslic->channel,PROSLIC_RAM_V_VLIM)*5)/6;
+  pProslic->mwiState.poll.step_size = (pProslic->mwiState.poll.von - pProslic->mwiState.poll.voff)/steps;
+  
+  pProslic->mwiState.state = PROSLIC_MWI_RAMP_ON;
+  pProslic->mwiState.ticks = pProslic->mwiState.poll.steps;
+
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/******************************************************************************/
+#ifdef SIVOICE_NEON_MWI_SUPPORT
+int ProSLIC_MWIRampStop(proslicChanType_ptr pProslic)
+{
+  /* Check if PROSLIC and enabled MWI, if not, ignore this request. */
+  if( (pProslic->channelType != PROSLIC)
+       || !(ReadReg(pProslic,pProslic->channel,PROSLIC_REG_USERSTAT) & SIL_MWI_USTAT_SET ) )
+  {
+    return RC_IGNORE;
+  }
+  pProslic->mwiState.state = PROSLIC_MWI_OFF;
+  
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+int ProSLIC_ToneGenStart (proslicChanType_ptr pProslic,uInt8 timerEn)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "timerEn = %u\n", timerEn);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  DEBUG_PRINT(pProslic, "%s%s on channel %d\n",LOGPRINT_PREFIX, __FUNCTION__,
+              pProslic->channel);
+
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_OCON);
+  data |= 0x11 + (timerEn ? 0x66 : 0);
+  return WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OCON,data);
+}
+
+/*****************************************************************************************************/
+int ProSLIC_ToneGenStop (proslicChanType_ptr pProslic)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "\n", NULL);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  DEBUG_PRINT(pProslic,"%s%s on channel %d\n",LOGPRINT_PREFIX, __FUNCTION__,
+              pProslic->channel);
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_OCON);
+  data &= ~(0x77);
+  return WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OCON,data);
+}
+
+/*****************************************************************************************************/
+int ProSLIC_RingStart (proslicChanType_ptr pProslic)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+  return(ProSLIC_SetLinefeedStatus(pProslic, LF_RINGING));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_RingStop (proslicChanType_ptr pProslic)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+  return(ProSLIC_SetLinefeedStatus(pProslic, LF_FWD_ACTIVE));
+}
+
+#ifndef DISABLE_FSK_SETUP
+/*****************************************************************************************************/
+int ProSLIC_CheckCIDBuffer (proslicChanType_ptr pProslic, uInt8 *fsk_buf_avail)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "\n", NULL);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  data = ReadReg(pProslic,pProslic->channel, PROSLIC_REG_IRQ1);
+#ifdef GCI_MODE
+  WriteReg(pProslic,pProslic->channel, PROSLIC_REG_IRQ1,data); /*clear (for GCI)*/
+#endif
+  *fsk_buf_avail = (data&0x40) ? 1 : 0;
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_EnableCID (proslicChanType_ptr pProslic)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "\n", NULL);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  DEBUG_PRINT(pProslic, "%sEnableCID on channel %d\n",LOGPRINT_PREFIX,
+              pProslic->channel);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OCON,0);
+
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE);
+  data |= 0xA;
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE,data);
+
+  return(WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OCON,0x5));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_DisableCID (proslicChanType_ptr pProslic)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  DEBUG_PRINT(pProslic, "%sDisableCID on channel %d\n",LOGPRINT_PREFIX,
+              pProslic->channel);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OCON,0);
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE);
+  data &= ~(0x8);
+
+  return(WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE,data));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_SendCID (proslicChanType_ptr pProslic, uInt8 *buffer,
+                     uInt8 numBytes)
+{
+  TRACEPRINT(pProslic, "numBytes = %u\n", numBytes);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  DEBUG_PRINT (pProslic, "%sSendCID on channel %d\n",LOGPRINT_PREFIX,
+               pProslic->channel);
+  while (numBytes-- > 0)
+  {
+    WriteReg(pProslic,pProslic->channel,PROSLIC_REG_FSKDAT,*(buffer++));
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_ModifyCIDStartBits(proslicChanType_ptr pProslic,
+                               uInt8 enable_startStop)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "enable_startStop = %u\n", enable_startStop);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE);
+
+  if(enable_startStop == FALSE)
+  {
+    data &= ~0x80;
+  }
+  else
+  {
+    data |= 0x80;
+  }
+
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE,data);
+
+  return RC_NONE;
+}
+#endif /* DISABLE_FSK_SETUP */
+/*****************************************************************************************************/
+int ProSLIC_PCMStart (proslicChanType_ptr pProslic)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  DEBUG_PRINT(pProslic, "%sPCMStart\n", LOGPRINT_PREFIX);
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_PCMMODE);
+  data |= 0x10;
+
+  return WriteReg(pProslic,pProslic->channel,PROSLIC_REG_PCMMODE,data);
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PCMStop (proslicChanType_ptr pProslic)
+{
+  uInt8 data;
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  DEBUG_PRINT(pProslic, "%sPCMStart\n", LOGPRINT_PREFIX);
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_PCMMODE);
+  data &= ~0x10;
+
+  return WriteReg(pProslic,pProslic->channel,PROSLIC_REG_PCMMODE,data);
+}
+
+#ifndef DISABLE_HOOKCHANGE
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_ResetDialPulseDetect
+**
+** Description:
+** reset dial pulse detection state machine (helper function for
+** ProSLIC_InitializeHookChangeDetect.
+*/
+static void ProSLIC_ResetDialPulseDetect(hookChangeType *pPulse)
+{
+  pPulse->currentPulseDigit = 0;
+  pPulse->lookingForTimeout = 0;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_InitializeHookChangeDetect
+**
+** Description:
+** Initialize dial pulse detection parameters
+*/
+int ProSLIC_InitializeHookChangeDetect(hookChangeType *pPulse,void *hookTime)
+{
+  TRACEPRINT_NOCHAN("\n", NULL);
+  pPulse->hookTime = hookTime;
+  pPulse->last_state_reported =  SI_HC_NO_ACTIVITY;
+  ProSLIC_ResetDialPulseDetect(pPulse);
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_HookChangeDetect
+**
+** Description:
+** implements pulse dial detection and should be called at every hook transition
+*/
+uInt8 ProSLIC_HookChangeDetect (proslicChanType *pProslic,
+                                hookChange_Cfg *pHookChangeCfg, hookChangeType *pHookChangeData)
+{
+  uInt8 hookStat;
+  int delta_time;
+
+  TRACEPRINT(pProslic, "\n", NULL);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  TimeElapsed(pProTimer,pHookChangeData->hookTime,&delta_time);
+  ProSLIC_ReadHookStatus(pProslic,&hookStat);
+
+  /* Did we have a hook state change? */
+  if(hookStat !=  pHookChangeData->last_hook_state)
+  {
+    pHookChangeData->last_hook_state = hookStat;
+    getTime(pProTimer,pHookChangeData->hookTime);
+    pHookChangeData->lookingForTimeout = 1;
+    if (hookStat == PROSLIC_OFFHOOK)
+    {
+      if ((delta_time >= (pHookChangeCfg->minOnHook))
+          && (delta_time <= (pHookChangeCfg->maxOnHook)))
+      {
+        pHookChangeData->currentPulseDigit++;
+      }
+      else
+      {
+        /* Did we see a hook flash? */
+        if( (delta_time >= pHookChangeCfg->minHookFlash)
+            && (delta_time <= pHookChangeCfg->maxHookFlash) )
+        {
+          pHookChangeData->last_state_reported = SI_HC_HOOKFLASH;
+          ProSLIC_ResetDialPulseDetect(pHookChangeData);
+          return SI_HC_HOOKFLASH;
+        }
+      }
+    }
+
+    return SI_HC_NEED_MORE_POLLS;
+  }
+
+  if( (pHookChangeData->lookingForTimeout == 1)
+      && (delta_time >=  pHookChangeCfg->minInterDigit) )
+  {
+
+    if(delta_time  > pHookChangeCfg->minHook)
+    {
+      if(pHookChangeData->last_hook_state == PROSLIC_ONHOOK)
+      {
+        ProSLIC_ResetDialPulseDetect(pHookChangeData);
+        pHookChangeData->last_state_reported = SI_HC_ONHOOK_TIMEOUT;
+        return SI_HC_ONHOOK_TIMEOUT;
+      }
+
+      if(pHookChangeData->last_hook_state == PROSLIC_OFFHOOK)
+      {
+        ProSLIC_ResetDialPulseDetect(pHookChangeData);
+
+        /* Check if we saw either a pulse digit or hook flash prior to this,
+         * if so, we're already offhook, so do not report a offhook event,
+         * just stop polling.
+         */
+        if((pHookChangeData->last_state_reported == SI_HC_ONHOOK_TIMEOUT)
+            || (pHookChangeData->last_state_reported == SI_HC_NO_ACTIVITY) )
+        {
+          pHookChangeData->last_state_reported = SI_HC_OFFHOOK_TIMEOUT;
+          return SI_HC_OFFHOOK_TIMEOUT;
+        }
+        else
+        {
+          return SI_HC_NO_ACTIVITY;
+        }
+      }
+    }
+    else
+    {
+      uInt8 last_digit = pHookChangeData->currentPulseDigit;
+
+      if(last_digit)
+      {
+        pHookChangeData->last_state_reported = last_digit;
+        ProSLIC_ResetDialPulseDetect(pHookChangeData);
+        return last_digit;
+      }
+    }
+    return SI_HC_NEED_MORE_POLLS;
+  }
+
+  return SI_HC_NEED_MORE_POLLS;
+}
+#endif /* DISABLE_HOOKCHANGE */
+
+/*****************************************************************************************************/
+int ProSLIC_DTMFReadDigit (proslicChanType_ptr pProslic,uInt8 *pDigit)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  DEBUG_PRINT(pProslic, "%sDTMFReadDigit on channel %d\n",LOGPRINT_PREFIX,
+              pProslic->channel);
+  *pDigit = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_TONDTMF) & 0xf;
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PLLFreeRunStart (proslicChanType_ptr hProslic)
+{
+  uInt8 tmp;
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_ZCAL_EN,0x00);
+  tmp = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE);
+
+  return(WriteReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE,tmp|0x4));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PLLFreeRunStop (proslicChanType_ptr hProslic)
+{
+  uInt8 tmp;
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  tmp = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE);
+  WriteReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE,tmp&~(0x4));
+
+  return WriteReg(hProslic,hProslic->channel,PROSLIC_REG_ZCAL_EN,0x04);
+}
+
+/*****************************************************************************************************/
+int ProSLIC_GetPLLFreeRunStatus (proslicChanType_ptr hProslic)
+{
+  uInt8 tmp;
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  tmp = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE);
+
+  if(tmp & 0x02)
+  {
+    return RC_PLL_FREERUN_ACTIVE;
+  }
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+#ifndef DISABLE_PULSEMETERING
+int ProSLIC_PulseMeterEnable (proslicChanType_ptr hProslic)
+{
+  uInt8 widebandEn;
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  widebandEn = ReadReg(hProslic,hProslic->channel,PROSLIC_REG_ENHANCE) & 0x01;
+
+  if (widebandEn)
+  {
+    DEBUG_PRINT (hProslic,
+                 "%s Pulse Metering is not supported while Wideband Mode is enabled.\n",
+                 LOGPRINT_PREFIX);
+  }
+
+#if defined (SI3217X) || defined (SI3218X) || defined (SI3226X) || defined (SI3228X) || defined(SI3219X)
+  if(!widebandEn && (0 
+#ifdef SI3217X
+      || (hProslic->deviceId->chipType >= SI32171
+          && hProslic->deviceId->chipType <= SI32179)
+#endif
+#ifdef SI3218X
+      ||(hProslic->deviceId->chipType >= SI32180
+         && hProslic->deviceId->chipType <= SI32189) 
+#endif
+#ifdef SI3219X
+      || (IS_SI3219X(hProslic->deviceId) )
+#endif
+#ifdef SI3226X
+      || (hProslic->deviceId->chipType >= SI32260
+          && hProslic->deviceId->chipType <= SI32269)
+#endif
+#ifdef SI3228X
+      || (hProslic->deviceId->chipType >= SI32280
+          && hProslic->deviceId->chipType <= SI32289 )
+#endif
+    ))
+  {
+    return WriteReg(hProslic,hProslic->channel,PROSLIC_REG_PMCON,ReadReg(hProslic,
+                    hProslic->channel,PROSLIC_REG_PMCON) | (0x01));
+  }
+#endif
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PulseMeterDisable (proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  return(WriteReg(hProslic,hProslic->channel,PROSLIC_REG_PMCON,ReadReg(hProslic,
+                  hProslic->channel,PROSLIC_REG_PMCON) & ~(0x05)));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PulseMeterStart (proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  return WriteReg(hProslic,hProslic->channel,PROSLIC_REG_PMCON,ReadReg(hProslic,
+                  hProslic->channel,PROSLIC_REG_PMCON) | (0x5));
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PulseMeterStop (proslicChanType_ptr hProslic)
+{
+  TRACEPRINT(hProslic, "\n", NULL);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return(WriteReg(hProslic,hProslic->channel,PROSLIC_REG_PMCON,ReadReg(hProslic,
+                    hProslic->channel,PROSLIC_REG_PMCON) & ~(0x04)));
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return(WriteReg(hProslic,hProslic->channel,PROSLIC_REG_PMCON,ReadReg(hProslic,
+                    hProslic->channel,PROSLIC_REG_PMCON) & ~(0x04)));
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return(WriteReg(hProslic,hProslic->channel,PROSLIC_REG_PMCON,ReadReg(hProslic,
+                    hProslic->channel,PROSLIC_REG_PMCON) & ~(0x04)));
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return ProSLIC_PulseMeterDisable(hProslic);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return ProSLIC_PulseMeterDisable(hProslic);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+#endif /* DISABLE_PULSEMETERING */
+/*****************************************************************************************************/
+int ProSLIC_SetDCDCInversionFlag (proslicChanType_ptr hProslic, uInt8 flag)
+{
+  TRACEPRINT(hProslic, "flag = %u\n", flag);
+
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  hProslic->dcdc_polarity_invert = flag;
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+
+int ProSLIC_PowerUpConverter (proslicChanType_ptr hProslic)
+{
+  if(hProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (hProslic->deviceId->chipType >= SI32171
+      && hProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_PowerUpConverter(hProslic);
+  }
+#endif
+
+#ifdef SI3218X
+  if (hProslic->deviceId->chipType >= SI32180
+      && hProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_PowerUpConverter(hProslic);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(hProslic->deviceId) )
+  {
+    return Si3219x_PowerUpConverter(hProslic);
+  }
+#endif
+
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_PowerUpConverter(hProslic);
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_PowerUpConverter(hProslic);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+/*****************************************************************************************************/
+static int ProSLIC_GetBatType(proslicChanType_ptr hProslic)
+{
+#ifdef SI3226X
+  if (hProslic->deviceId->chipType >= SI32260
+      && hProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_General_Configuration.batType;
+  }
+#endif
+
+#ifdef SI3228X
+  if (hProslic->deviceId->chipType >= SI32280
+      && hProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_General_Configuration.batType;
+  }
+#endif
+
+#if !defined(SI3226X) && !defined(SI3228X)
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+#endif
+  return BO_DCDC_UNKNOWN;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_PowerDownConverter (proslicChanType_ptr pProslic)
+{
+  errorCodeType error = RC_NONE;
+  int32 vbat;
+  int timer = 0;
+
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  /* Force channel out of powersavings mode and then put it in open state */
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_LINEFEED,LF_FWD_OHT);
+  Delay(pProTimer,10);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_LINEFEED, LF_OPEN);
+  Delay(pProTimer,50);
+
+  /* Don't try to shutdown converter if we're using external supplies or if the
+     converter is already shutdown.
+  */
+  if((ProSLIC_GetBatType(pProslic) == BO_DCDC_EXTERNAL) ||
+      (ReadRAM(pProslic,pProslic->channel,PROSLIC_RAM_PD_DCDC) & 0x100000) )
+  {
+    return RC_NONE;
+  }
+
+  WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_PD_DCDC,0x900000L);
+  Delay(pProTimer,50);
+
+  do
+  {
+    vbat = ReadRAM(pProslic, pProslic->channel, PROSLIC_RAM_MADC_VBAT);
+    if(vbat & 0x10000000L)
+    {
+      vbat |= 0xF0000000L;
+    }
+    Delay(pProTimer,10);
+  }
+  while((vbat > COMP_5V) && (timer++ < PROSLIC_TIMEOUT_DCDC_DOWN));
+
+  DEBUG_PRINT(pProslic, "%s VBAT Down = %d.%d v\n", LOGPRINT_PREFIX,
+              (int)((vbat/SCALE_V_MADC)/1000),
+              SIVOICE_ABS(((vbat/SCALE_V_MADC) - (vbat/SCALE_V_MADC)/1000*1000)));
+
+  if(timer > PROSLIC_TIMEOUT_DCDC_DOWN)
+  {
+    /* Error handling - shutdown converter, disable channel, set error tag */
+    pProslic->channelEnable = 0;
+    pProslic->error = error = RC_VBAT_DOWN_TIMEOUT;
+    DEBUG_PRINT(pProslic, "%sDCDC Power Down timeout channel %d\n", LOGPRINT_PREFIX,
+                pProslic->channel);
+  }
+  return error;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_LBCal (proslicChanType_ptr *pProslic, int size)
+{
+  int k;
+  int timeout;
+  uInt8 data;
+  uInt8 lfState, enhance_value;
+  TRACEPRINT(*pProslic, "size = %d\n", size);
+
+  if((*pProslic)->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  /* For all channels, save settings, initiate LBCAL */
+  for(k = 0; k < size; k++)
+  {
+    if( (pProslic[k]->channelEnable) && (pProslic[k]->channelType == PROSLIC) )
+    {
+      DEBUG_PRINT(pProslic[k], "%sStarting LB Cal on channel %d\n", LOGPRINT_PREFIX,
+                  pProslic[k]->channel);
+      /* Preserve old settings */
+      lfState = ReadReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_LINEFEED);
+      enhance_value = ReadReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_ENHANCE);
+      ProSLIC_SetPowersaveMode(pProslic[k], PWRSAVE_DISABLE);
+      ProSLIC_SetLinefeedStatus(pProslic[k], LF_FWD_ACTIVE);
+      WriteReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_CALR0, CAL_LB_ALL);
+      WriteReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_CALR3,  0x80);
+      pProslic[k]->error = RC_CAL_TIMEOUT; /* Assume failure */
+
+      timeout = 0;
+      do
+      {
+        data = ReadReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_CALR3);
+        DelayX(*pProslic, 10);
+        timeout++;
+      }
+      while((data & 0x80) && (timeout < TIMEOUT_LB_CAL));
+
+      if( (data & 0x80) )
+      {
+        DEBUG_PRINT(pProslic[k], "%sLB Cal timeout on channel %d\n", LOGPRINT_PREFIX,
+                    pProslic[k]->channel);
+        WriteReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_LINEFEED, LF_OPEN);
+        return RC_CAL_TIMEOUT;
+      }
+      else
+      {
+        WriteReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_LINEFEED, lfState);
+        WriteReg(pProslic[k], pProslic[k]->channel, PROSLIC_REG_ENHANCE, enhance_value);
+        pProslic[k]->error = RC_NONE;
+      }
+    }
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+#define PROSLIC_RAM_CMDAC_FWD 1476
+#define PROSLIC_RAM_CMDAC_REV 1477
+#define PROSLIC_RAM_CAL_TRNRD_DACT 1458
+#define PROSLIC_RAM_CAL_TRNRD_DACR 1459
+
+int ProSLIC_GetLBCalResult (proslicChanType *pProslic,int32 *result1,
+                            int32 *result2, int32 *result3, int32 *result4)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  *result1 = ReadRAM(pProslic, pProslic->channel, PROSLIC_RAM_CMDAC_FWD);
+  *result2 = ReadRAM(pProslic, pProslic->channel, PROSLIC_RAM_CMDAC_REV);
+  *result3 = ReadRAM(pProslic, pProslic->channel, PROSLIC_RAM_CAL_TRNRD_DACT);
+  *result4 = ReadRAM(pProslic, pProslic->channel, PROSLIC_RAM_CAL_TRNRD_DACR);
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_GetLBCalResultPacked (proslicChanType *pProslic,int32 *result)
+{
+  int32 results[4];
+  int rc;
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  rc = ProSLIC_GetLBCalResult(pProslic, &(results[0]), &(results[1]),
+                             &(results[2]), &(results[3]));
+  if(rc == RC_NONE)
+  {
+    /*
+      Bits 31:24   CMDAC_FWD[25:18]
+      Bits 23:16   CMDAC_REV[25:18]
+      Bits 15:8    CAL_TRNRD_DACT[20:13]
+      Bits 7:0     CAL_TRNRD_DACR[20:13]
+    */
+    *result = (results[0]<<6) & 0xff000000L;
+    *result |=(results[1]>>1) & 0x00ff0000L;
+    *result |=(results[2]>>5) & 0x0000ff00L;
+    *result |=(results[3]>>13)& 0x000000ffL;
+  }
+
+  return rc;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_LoadPreviousLBCal (proslicChanType *pProslic,int32 result1,
+                               int32 result2,int32 result3,int32 result4)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_CMDAC_FWD,result1);
+  WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_CMDAC_REV,result2);
+  WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_CAL_TRNRD_DACT,result3);
+  WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_CAL_TRNRD_DACR,result4);
+
+#ifdef API_TEST
+  ramVal = ReadRAM(pProslic,pProslic->channel,PROSLIC_RAM_CMDAC_FWD);
+  LOGPRINT ("%s UNPACKED CMDAC_FWD = %08x\n", LOGPRINT_PREFIX, ramVal);
+  ramVal = ReadRAM(pProslic, pProslic->channel,PROSLIC_RAM_CMDAC_REV);
+  LOGPRINT ("%s UNPACKED CMDAC_REF = %08x\n", LOGPRINT_PREFIX, ramVal);
+  ramVal = ReadRAM(pProslic,pProslic->channel,PROSLIC_RAM_CAL_TRNRD_DACT);
+  LOGPRINT ("%s UNPACKED CAL_TRNRD_DACT = %08x\n", LOGPRINT_PREFIX, ramVal);
+  ramVal = ReadRAM(pProslic,pProslic->channel,PROSLIC_RAM_CAL_TRNRD_DACR);
+  LOGPRINT ("%s UNPACKED CAL_TRNRD_DACR = %08x\n", LOGPRINT_PREFIX, ramVal);
+#endif
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_LoadPreviousLBCalPacked (proslicChanType *pProslic,int32 *result)
+{
+  ramData ramVal[4];
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+  ramVal[0] = (*result&0xff000000L)>>6;
+  ramVal[1] = (*result&0x00ff0000L)<<1;
+  ramVal[2] = (*result&0x0000ff00L)<<5;
+  ramVal[3] = (*result&0x000000ffL)<<13;
+
+  return ProSLIC_LoadPreviousLBCal(pProslic, ramVal[0], ramVal[1], ramVal[2],
+                                   ramVal[3]);
+}
+
+/*****************************************************************************************************/
+int ProSLIC_dbgSetDCFeedVopen (proslicChanType *pProslic, uInt32 v_vlim_val,
+                               int32 preset)
+{
+  TRACEPRINT(pProslic, "v_vlim_val = %u preset = %d\n", v_vlim_val, preset);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_dbgSetDCFeedVopen (pProslic,v_vlim_val,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_dbgSetDCFeedVopen (pProslic,v_vlim_val,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_dbgSetDCFeedVopen (pProslic,v_vlim_val,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_dbgSetDCFeedVopen (pProslic,v_vlim_val,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_dbgSetDCFeedVopen (pProslic,v_vlim_val,preset);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_dbgSetDCFeedIloop (proslicChanType *pProslic, uInt32 i_ilim_val,
+                               int32 preset)
+{
+  TRACEPRINT(pProslic, "i_ilim_val = %u preset = %d\n", i_ilim_val, preset);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_dbgSetDCFeedIloop (pProslic,i_ilim_val,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_dbgSetDCFeedIloop (pProslic,i_ilim_val,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_dbgSetDCFeedIloop (pProslic,i_ilim_val,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_dbgSetDCFeedIloop (pProslic,i_ilim_val,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_dbgSetDCFeedIloop (pProslic,i_ilim_val,preset);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_dbgSetRinging (proslicChanType *pProslic,
+                           ProSLIC_dbgRingCfg *ringCfg, int preset)
+{
+  TRACEPRINT(pProslic, "preset = %d\n", preset);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_dbgSetRinging (pProslic,ringCfg,preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_dbgSetRinging (pProslic,ringCfg,preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_dbgSetRinging (pProslic,ringCfg,preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_dbgSetRinging (pProslic,ringCfg,preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_dbgSetRinging (pProslic,ringCfg,preset);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_dbgSetRXGain (proslicChanType *pProslic, int32 gain,
+                          int impedance_preset, int audio_gain_preset)
+{
+  TRACEPRINT(pProslic, "gain = %d imp_preset = %d audio_gain_preset = %d\n", gain,
+             impedance_preset, audio_gain_preset);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_dbgSetRXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_dbgSetRXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_dbgSetRXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_dbgSetRXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_dbgSetRXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_dbgSetTXGain (proslicChanType *pProslic, int32 gain,
+                          int impedance_preset, int audio_gain_preset)
+{
+  TRACEPRINT(pProslic, "gain = %d imp_preset = %d audio_gain_preset = %d\n", gain,
+             impedance_preset, audio_gain_preset);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_dbgSetTXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_dbgSetTXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_dbgSetTXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_dbgSetTXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_dbgSetTXGain (pProslic,gain,impedance_preset,audio_gain_preset);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_LineMonitor
+**
+** Description:
+** Generic monitoring function
+**
+** Returns:
+** 0
+*/
+
+int ProSLIC_LineMonitor (proslicChanType *pProslic, proslicMonitorType *monitor)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_LineMonitor (pProslic, monitor);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_LineMonitor (pProslic, monitor);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_LineMonitor (pProslic, monitor);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_LineMonitor (pProslic, monitor);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_LineMonitor (pProslic, monitor);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_PSTNCheck
+**
+** Description:
+** Monitor for excessive longitudinal current, which
+** would be present if a live pstn line was connected
+** to the port.
+**
+** Returns:
+** 0 - no pstn detected
+** 1 - pstn detected
+*/
+int ProSLIC_PSTNCheck (proslicChanType *pProslic,
+                       proslicPSTNCheckObjType *pPSTNCheck)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_PSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_PSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_PSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_PSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_PSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_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_IGNORE - non-ProSLIC channel
+** RC_COMPLETE_NO_ERR - ProSLIC does not support feature.
+** RC_PSTN_OPEN_FEMF | RC_COMPLETE_NO_ERR - test completed.
+**
+*/
+#ifdef PSTN_DET_ENABLE
+int ProSLIC_DiffPSTNCheck (proslicChanType *pProslic,
+                           proslicDiffPSTNCheckObjType *pPSTNCheck)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    return Si3217x_DiffPSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3218X
+  if (pProslic->deviceId->chipType >= SI32180
+      && pProslic->deviceId->chipType <= SI32189)
+  {
+    return Si3218x_DiffPSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3219X
+  if ( IS_SI3219X(pProslic->deviceId) )
+  {
+    return Si3219x_DiffPSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3226X
+  if (pProslic->deviceId->chipType >= SI32260
+      && pProslic->deviceId->chipType <= SI32269)
+  {
+    return Si3226x_DiffPSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+#ifdef SI3228X
+  if (pProslic->deviceId->chipType >= SI32280
+      && pProslic->deviceId->chipType <= SI32289)
+  {
+    return Si3228x_DiffPSTNCheck (pProslic,pPSTNCheck);
+  }
+#endif
+
+  return RC_COMPLETE_NO_ERR;
+}
+#endif
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_CreatePSTNCheckObj
+**
+** Description:
+** Allocate memory for pstnCheckObj
+**
+** Returns:
+** RC_NONE
+** RC_NO_MEM if failed to allocate memory.
+** RC_UNSUPPORTED_FEATER if malloc disabled
+*/
+int ProSLIC_CreatePSTNCheckObjs(proslicPSTNCheckObjType_ptr *pstnCheckObj,
+                                unsigned int num_objs)
+{
+  TRACEPRINT_NOCHAN("num_objs = %u\n", num_objs);
+#ifndef DISABLE_MALLOC
+  *pstnCheckObj = SIVOICE_CALLOC(sizeof(proslicPSTNCheckObjType),num_objs);
+  if(*pstnCheckObj == NULL)
+  {
+#ifdef ENABLE_DEBUG
+    LOGPRINT("%s: %s: failed to allocate memory", LOGPRINT_PREFIX, __FUNCTION__);
+#endif
+    return RC_NO_MEM;
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pstnCheckObj);
+  SILABS_UNREFERENCED_PARAMETER(num_objs);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_CreateDiffPSTNCheckObjs
+**
+** Description:
+** Allocate memory for proslicDiffPstnCheckObjs
+**
+** Returns:
+** RC_NONE
+** RC_NO_MEM if failed to allocate memory.
+** RC_UNSUPPORTED_FEATURE if malloc disabled
+*/
+
+#ifdef PSTN_DET_ENABLE
+int ProSLIC_CreateDiffPSTNCheckObjs(proslicDiffPSTNCheckObjType_ptr
+                                    *pstnCheckObj, unsigned int num_objs)
+{
+  TRACEPRINT_NOCHAN("num_objs = %u\n", num_objs);
+
+#ifndef DISABLE_MALLOC
+  *pstnCheckObj = SIVOICE_CALLOC(sizeof(proslicDiffPSTNCheckObjType),num_objs);
+  if(*pstnCheckObj == NULL)
+  {
+#ifdef ENABLE_DEBUG
+    LOGPRINT("%s: %s: failed to allocate memory", LOGPRINT_PREFIX, __FUNCTION__);
+#endif
+    return RC_NO_MEM;
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pstnCheckObj);
+  SILABS_UNREFERENCED_PARAMETER(num_objs);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+#endif
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_DestroyPSTNCheckObjs
+**
+** Description:
+** Free memory for pstnCheckObj
+**
+** Returns:
+** RC_NONE
+** RC_UNSUPPORTED_FEATER if malloc disabled
+*/
+int ProSLIC_DestroyPSTNCheckObjs(proslicPSTNCheckObjType_ptr *pstnCheckObj)
+{
+  TRACEPRINT_NOCHAN("\n", NULL);
+
+#ifndef DISABLE_MALLOC
+  if(pstnCheckObj)
+  {
+    SIVOICE_FREE((proslicPSTNCheckObjType_ptr)*pstnCheckObj);
+  }
+
+  return RC_NONE;
+
+#else
+  SILABS_UNREFERENCED_PARAMETER(pstnCheckObj);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_DestroyDiffPSTNCheckObjs
+**
+** Description:
+** Free memory for pstnDiffCheckObj
+**
+** Returns:
+** RC_NONE
+** RC_UNSUPPORTED_FEATER if malloc disabled
+*/
+#ifdef PSTN_DET_ENABLE
+int ProSLIC_DestroyDiffPSTNCheckObjs(proslicDiffPSTNCheckObjType_ptr
+                                     *pstnCheckObj)
+{
+  TRACEPRINT_NOCHAN("\n", NULL);
+
+#ifndef DISABLE_MALLOC
+  if(pstnCheckObj)
+  {
+    SIVOICE_FREE((proslicDiffPSTNCheckObjType_ptr)*pstnCheckObj);
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pstnCheckObj);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+#endif
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_InitPSTNCheckObj
+**
+** Description:
+** Initialize pstnCheckObj structure members
+**
+** Returns:
+** RC_NONE
+*/
+int ProSLIC_InitPSTNCheckObj(proslicPSTNCheckObjType_ptr pstnCheckObj,
+                             int32 avgThresh, int32 singleThresh, uInt8 samples)
+{
+  TRACEPRINT_NOCHAN("avgThres = %d singleThresh = %d samples = %u\n", avgThresh,
+                    avgThresh, samples);
+
+  pstnCheckObj->avgThresh = avgThresh;
+  pstnCheckObj->singleThresh = singleThresh;
+  pstnCheckObj->samples = samples;
+  pstnCheckObj->avgIlong = 0;
+  pstnCheckObj->count = 0;
+  pstnCheckObj->buffFull = 0;
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_InitDiffPSTNCheckObj
+**
+** Description:
+** Initialize pstnCheckObj structure members
+**
+** Returns:
+** RC_NONE
+*/
+#ifdef PSTN_DET_ENABLE
+int ProSLIC_InitDiffPSTNCheckObj(proslicDiffPSTNCheckObjType_ptr
+                                 pstnDiffCheckObj,
+                                 int preset1,
+                                 int preset2,
+                                 int entry_preset,
+                                 int femf_enable)
+{
+  TRACEPRINT_NOCHAN("p1 = %d p2 = %d ep = %d femf_enable = %d\n", preset1,
+                    preset2, entry_preset, femf_enable);
+
+  pstnDiffCheckObj->samples = PSTN_DET_DIFF_SAMPLES;
+  pstnDiffCheckObj->max_femf_vopen = PSTN_DET_MAX_FEMF;
+  pstnDiffCheckObj->entryDCFeedPreset = entry_preset;
+  pstnDiffCheckObj->dcfPreset1 = preset1;
+  pstnDiffCheckObj->dcfPreset2 = preset2;
+  pstnDiffCheckObj->femf_enable = femf_enable;
+  pstnDiffCheckObj->pState.stage = 0;
+  pstnDiffCheckObj->pState.sampleIterations = 0;
+  pstnDiffCheckObj->pState.waitIterations = 0;
+
+  return RC_NONE;
+}
+#endif
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_SetPwrsaveMode
+**
+** Description:
+** Enable or disable powersave mode
+**
+** Returns:
+** RC_NONE
+*/
+#define PROSLIC_REG_ENHANCE 47
+
+int ProSLIC_SetPowersaveMode (proslicChanType *pProslic, int pwrsave)
+{
+  uInt8 regData;
+  TRACEPRINT(pProslic, "pwrsave = %d\n", pwrsave);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  regData = ReadReg(pProslic,pProslic->channel, PROSLIC_REG_ENHANCE);
+
+  if(pwrsave == PWRSAVE_DISABLE)
+  {
+#ifdef SI3217X
+    if (pProslic->deviceId->chipType >= SI32171
+        && pProslic->deviceId->chipType <= SI32179)
+    {
+      regData &= 0x27;
+    }
+    else
+    {
+#endif
+      regData &= 0x07;
+#ifdef SI3217X
+    }
+#endif
+  }
+  else
+  {
+    regData |= 0x10;
+  }
+
+  return WriteReg(pProslic,pProslic->channel, PROSLIC_REG_ENHANCE, regData);
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_SetDAAEnable
+**
+** Description:
+** Enable or disable adjacent FXO (Si32178 only)
+**
+** Returns:
+** RC_NONE
+*/
+int ProSLIC_SetDAAEnable (proslicChanType *pProslic, int enable)
+{
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+#ifdef SI3217X
+  return Si3217x_SetDAAEnable (pProslic,enable);
+#else
+  SILABS_UNREFERENCED_PARAMETER(enable);
+  return RC_NONE;
+#endif
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_SetUserMode
+**
+** Description: Enables User Access Mode (UAM) if the part supports it.
+**
+** Returns:
+** RC_NONE if successful.
+*/
+#define PROSLIC_REG_USERMODE_ENABLE 126
+
+int ProSLIC_SetUserMode(proslicChanType *pProslic,BOOLEAN isEnabled,
+                        BOOLEAN isBcast)
+{
+  uInt8 data;
+  uInt8 channel;
+
+  TRACEPRINT(pProslic, "enable = %d bcast = %d\n", (int)isEnabled, (int)isBcast);
+
+  if(isEnabled == FALSE)
+  {
+    return RC_NONE;
+  }
+
+  if( pProslic->channelType != PROSLIC )
+  {
+    return RC_UNSUPPORTED_FEATURE;
+  }
+
+  if(isBcast == TRUE)
+  {
+    channel = PROSLIC_CHAN_BROADCAST;
+  }
+  else
+  {
+    channel = pProslic->channel;
+  }
+
+  data = ReadReg(pProslic,pProslic->channel,
+                 PROSLIC_REG_USERMODE_ENABLE); /*we check first channel. we assume all channels same user mode state for broadcast */
+
+  if (((data&1) != 0) == isEnabled)
+  {
+    return RC_NONE;
+  }
+
+  WriteReg(pProslic,channel,PROSLIC_REG_USERMODE_ENABLE,2);
+  WriteReg(pProslic,channel,PROSLIC_REG_USERMODE_ENABLE,8);
+  WriteReg(pProslic,channel,PROSLIC_REG_USERMODE_ENABLE,0xe);
+  return WriteReg(pProslic,channel,PROSLIC_REG_USERMODE_ENABLE,0);
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_isReinitRequired
+**
+** Description:
+** Checks for improper ring exit
+**
+** Returns:
+** RC_NONE                -  Reinit not required
+** RC_REINIT_REQUIRED     -  Corrupted state machine - reinit required
+**
+*/
+
+int ProSLIC_isReinitRequired(proslicChanType *pProslic)
+{
+  uInt8 lf;
+  ramData rkdc_sum;
+  TRACEPRINT(pProslic, "\n", NULL);
+
+  if( pProslic->channelType != PROSLIC)
+  {
+    return RC_IGNORE;
+  }
+
+  /* Check for improper ring exit which may cause dcfeed corruption */
+
+  lf = ReadReg(pProslic, pProslic->channel,PROSLIC_REG_LINEFEED);
+  rkdc_sum = ReadRAM(pProslic,pProslic->channel,PROSLIC_RAM_RDC_SUM);
+  DEBUG_PRINT(pProslic, "%sisReinitRequired: Linefeed = 0x%02X RDC_SUM = %d\n",
+              LOGPRINT_PREFIX, (int)lf, (int) rkdc_sum);
+  if((rkdc_sum & 0x400000)&&(lf != 0x44))
+  {
+    return RC_REINIT_REQUIRED;
+  }
+  else
+  {
+    return RC_NONE;
+  }
+}
+
+/*****************************************************************************************************/
+/*
+** Function: LoadRegTable
+**
+** Description:
+** Generic function to load register/RAM with predefined addr/value
+*/
+int ProSLIC_LoadRegTable (proslicChanType *pProslic, 
+                          const ProslicRAMInit *pRamTable,
+                          const ProslicRegInit *pRegTable, 
+                          int broadcast)
+{
+  uInt16 i;
+  uInt8 channel;
+
+  TRACEPRINT(pProslic, "bcast = %d\n", broadcast);
+  /* DAA doesn't have a RAM table.. skip it... */
+  if( (pRamTable != 0)
+      && (pProslic->channelType != PROSLIC) )
+  {
+    return RC_IGNORE;
+  }
+
+  if (broadcast)
+  {
+    channel = PROSLIC_CHAN_BROADCAST;
+  }
+  else
+  {
+    channel = pProslic->channel;
+  }
+
+  i=0;
+  if (pRamTable != 0)
+  {
+    while (pRamTable[i].address != 0xffff)
+    {
+      WriteRAM(pProslic,channel,pRamTable[i].address,pRamTable[i].initValue);
+      i++;
+    }
+  }
+  i=0;
+  if (pRegTable != 0)
+  {
+    while (pRegTable[i].address != 0xff)
+    {
+      WriteReg(pProslic,channel,pRegTable[i].address,pRegTable[i].initValue);
+      i++;
+    }
+  }
+
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: LoadRegTables
+**
+** Description:
+** Generic function to load register/RAM with predefined addr/value
+*/
+
+int ProSLIC_LoadRegTables(proslicChanType_ptr *pProslic,
+                          const ProslicRAMInit *pRamTable, const ProslicRegInit *pRegTable, int size)
+{
+  int i;
+  TRACEPRINT(*pProslic, "size = %d\n", size);
+  for (i=0; i<size; i++)
+  {
+    if (pProslic[i]->channelEnable)
+    {
+      ProSLIC_LoadRegTable(pProslic[i],pRamTable,pRegTable,FALSE);
+    }
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_UnsupportedFeatureNoArg(proslicChanType_ptr pProslic,
+                                    const char *function_name)
+{
+#ifdef ENABLE_DEBUG
+  LOGPRINT("%s: unsupported %s was called on channel %d\n", LOGPRINT_PREFIX,
+           function_name, pProslic->channel);
+#else
+  SILABS_UNREFERENCED_PARAMETER(pProslic);
+  SILABS_UNREFERENCED_PARAMETER(function_name);
+#endif
+  return RC_UNSUPPORTED_FEATURE;
+}
+
+/*****************************************************************************************************/
+/*
+** Function: ProSLIC_PSTN_delay_poll
+**
+** Description:
+** Delay function called within PSTN detection functions
+**
+** Return Value:
+** none
+*/
+#ifdef PSTN_DET_ENABLE
+void ProSLIC_PSTN_delay_poll(proslicTestStateType *pState, uInt16 delay)
+{
+  uInt16 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: ProSLIC_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 ProSLIC_Calibrate(proslicChanType_ptr *pProslic, int maxChan, uInt8 *calr,
+                      int maxTime)
+{
+  int i,j, cal_en;
+  int cal_en_chan = 0;
+  int timer = 0;
+
+  TRACEPRINT(*pProslic, "maxChan = %d time = %d\n", maxChan, maxTime );
+
+  if ((*pProslic)->channelType != PROSLIC)
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+
+  for(i = 0; i < maxChan; i++)
+  {
+    if((pProslic[i]->channelEnable)&&(pProslic[i]->channelType == PROSLIC))
+    {
+      for(j = 0; j < 4; j++)
+      {
+        WriteReg(pProslic[i], pProslic[i]->channel, (PROSLIC_REG_CALR0+j), calr[j]);
+      }
+    }
+  }
+
+  /* Wait for calibration to complete */
+  do
+  {
+    cal_en = 0;
+    DelayX(*pProslic, 10);
+    for(i = 0; i < maxChan; i++)
+    {
+      if( (pProslic[i]->channelEnable) && (pProslic[i]->channelType == PROSLIC))
+      {
+        cal_en_chan = ReadReg(pProslic[i], pProslic[i]->channel, PROSLIC_REG_CALR3);
+        if( (cal_en_chan & 0x80) && (timer == maxTime) )
+        {
+          DEBUG_PRINT(pProslic[i], "%sCalibration timed out on channel %d\n",
+                      LOGPRINT_PREFIX, pProslic[i]->channel);
+          pProslic[i]->channelEnable = 0;
+          pProslic[i]->error = RC_CAL_TIMEOUT;
+        }
+        cal_en |= cal_en_chan;
+      }
+    }
+  }
+  while( (timer++ <= maxTime) && (cal_en & 0x80) );
+
+  if(timer <= maxTime)
+  {
+    return RC_NONE;
+  }
+  else
+  {
+    return RC_CAL_TIMEOUT;
+  }
+}
+/*****************************************************************************************************/
+/* This function is used by the xxxx_Init_with_Options - do not call this directly... */
+int ProSLIC_ReInit_helper(proslicChanType_ptr *pProslic, int size,
+                          initOptionsType init_option, int numChanPerDevice)
+{
+  int i;
+
+  /* Preserve linefeed state.. */
+  for(i = 0; i < size; i++)
+  {
+    pProslic[i]->scratch = ReadReg( pProslic[i], pProslic[i]->channel,
+                                   PROSLIC_REG_LINEFEED);
+    ProSLIC_PowerDownConverter( pProslic[i] );
+
+    /* Clear MSTRSTAT on a device basis */
+    if( (numChanPerDevice == 1) 
+      || ((numChanPerDevice == 2) && ((i&1) == 0)  ) )
+    {
+      ProSLIC_WriteReg(pProslic[i], PROSLIC_REG_MSTRSTAT, 0xFF); /* Clear master status register */
+    }
+  }
+
+  DelayX(*pProslic, 10); /* Wait to ensure system is powered down... */
+
+  /* Do a soft reset if reinit is requested...*/
+  if(init_option == INIT_REINIT)
+  {
+    for(i = 0; i < size; i++)
+    {
+      if(numChanPerDevice == 2) 
+      {
+        WriteReg(pProslic[i], (pProslic[i])->channel, PROSLIC_REG_RESET,
+                 (((pProslic[i])->channel)&1)+1); /* reset 1 channel at a time */
+      }
+      else
+      {
+        WriteReg(pProslic[i], (pProslic[i])->channel, PROSLIC_REG_RESET, 1);
+      }
+
+      pProslic[i]->error = RC_NONE; /* Clear any errors we may have seen in powering down the converter */
+    }
+    DelayX(*pProslic, 100); /* Wait for a soft reset */
+
+  }
+  return RC_NONE;
+}
+
+/*****************************************************************************************************/
+int ProSLIC_SoftReset(proslicChanType_ptr pProslic, uInt16 resetOptions)
+{
+  uInt8 data;
+
+  TRACEPRINT(pProslic, "reset option: %d\n",resetOptions);
+
+  /* We can't use channelType since it may not been set.  We assume at least 
+   * SWInit was called... */
+  if( pProslic->deviceId->chipType == SI3050 )
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+
+  /* Check if we're in free-run mode, if so abort */
+  data = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_ENHANCE);
+
+  if(data & 0x6)
+  {
+    return RC_PLL_FREERUN_ACTIVE;
+  }
+
+  if(resetOptions & PROSLIC_BCAST_RESET)
+  {
+    return WriteReg(pProslic, PROSLIC_CHAN_BROADCAST, PROSLIC_REG_RESET, (uInt8)(resetOptions & 0xFF));
+  }
+  else
+  {
+    return WriteReg(pProslic, pProslic->channel, PROSLIC_REG_RESET, (uInt8)(resetOptions & 0xFF));
+  }
+}
+
+/*****************************************************************************************************/
+#ifndef DISABLE_TONE_SETUP
+int ProSLIC_ToneGenSetupPtr(proslicChanType_ptr pProslic, ProSLIC_Tone_Cfg *cfg)
+{
+  TRACEPRINT(pProslic, "\n",NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+
+  WriteRAM(pProslic, pProslic->channel,PROSLIC_RAM_OSC1FREQ, cfg->osc1.freq);
+  WriteRAM(pProslic, pProslic->channel,PROSLIC_RAM_OSC1AMP, cfg->osc1.amp);
+  WriteRAM(pProslic, pProslic->channel,PROSLIC_RAM_OSC1PHAS, cfg->osc1.phas);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O1TAHI,cfg->osc1.tahi);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O1TALO,cfg->osc1.talo);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O1TIHI,cfg->osc1.tihi);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O1TILO,cfg->osc1.tilo);
+
+  WriteRAM(pProslic, pProslic->channel,PROSLIC_RAM_OSC2FREQ, cfg->osc2.freq);
+  WriteRAM(pProslic, pProslic->channel,PROSLIC_RAM_OSC2AMP, cfg->osc2.amp);
+  WriteRAM(pProslic, pProslic->channel,PROSLIC_RAM_OSC2PHAS, cfg->osc2.phas);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O2TAHI,cfg->osc2.tahi);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O2TALO,cfg->osc2.talo);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O2TIHI,cfg->osc2.tihi);
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_O2TILO,cfg->osc2.tilo);
+
+
+  WriteReg(pProslic, pProslic->channel,PROSLIC_REG_OMODE,cfg->omode);
+  return RC_NONE;
+}
+#endif /* DISABLE_TONE_SETUP */
+
+/*****************************************************************************************************/
+#ifndef DISABLE_FSK_SETUP
+int ProSLIC_FSKSetupPtr (proslicChanType_ptr pProslic, ProSLIC_FSK_Cfg *cfg)
+{
+  uInt8 data;
+  int i;
+
+  TRACEPRINT(pProslic, "\n",NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_FSKDEPTH,
+           0x08); /* Clear Buffer */
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_O1TAHI,0);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_O1TIHI,0);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_O1TILO,0);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_O1TALO,0x13);
+
+  data = ReadReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE);
+  if (cfg->eightBit)
+  {
+    data |= 0x80;
+  }
+  else
+  {
+    data &= ~(0x80);
+  }
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_FSKDEPTH,cfg->fskdepth);
+  WriteReg(pProslic,pProslic->channel,PROSLIC_REG_OMODE,data);
+
+  for(i = 0; i < 2; i++)
+  {
+    WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_FSK01+i,cfg->fsk[i]);
+    WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_FSKAMP0+i,cfg->fskamp[i]);
+    WriteRAM(pProslic,pProslic->channel,PROSLIC_RAM_FSKFREQ0+i,cfg->fskfreq[i]);
+  }
+  return RC_NONE;
+}
+#endif
+
+/*****************************************************************************************************/
+int ProSLIC_EnableFastRingStart(proslicChanType_ptr pProslic, BOOLEAN isEnabled)
+{
+  uInt8 data;
+
+  TRACEPRINT(pProslic, "\n",NULL);
+
+  if(pProslic->channelType != PROSLIC)
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+#if defined(SI3217X) && !defined(Si3217X_REVC_ONLY)
+  if (pProslic->deviceId->chipType >= SI32171
+      && pProslic->deviceId->chipType <= SI32179)
+  {
+    if(pProslic->deviceId->chipRev < 2)
+    {
+      return RC_UNSUPPORTED_FEATURE;
+    }
+  }
+#endif
+
+  data = ReadReg(pProslic, pProslic->channel, PROSLIC_REG_USERSTAT);
+
+  if( isEnabled )
+  {
+    data |= 8;
+  }
+  else
+  {
+    data &= ~8;
+  }
+
+  return WriteReg(pProslic, pProslic->channel, PROSLIC_REG_USERSTAT, data);
+}
+
diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/proslic_tstin.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/proslic_tstin.c
new file mode 100644
index 0000000..f8f7a99
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/proslic_tstin.c
@@ -0,0 +1,1580 @@
+// SPDX-License-Identifier: GPL-2.0

+/*

+ * Author(s):

+ * cdp

+ *

+ * 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 interface file for the ProSLIC test-in functions.

+ *

+ *

+ */

+

+#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 "../config_inc/proslic_api_config.h"

+#include "../inc/proslic_tstin.h"

+

+#ifdef SI3217X

+#include "si3217x.h"

+#include "si3217x_intf.h"

+#endif

+#ifdef SI3218X

+#include "../inc/si3218x.h"

+#include "../inc/si3218x_intf.h"

+#endif

+#ifdef SI3219X

+#include "si3219x.h"

+#include "si3219x_intf.h"

+#endif

+#ifdef SI3226X

+#include "si3226x.h"

+#include "si3226x_intf.h"

+#endif

+#ifdef SI3228X

+#include "si3228x.h"

+#include "si3228x_intf.h"

+#endif

+

+/*

+** Function Pointer Macros

+*/

+#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

+

+/*

+* Valid Device Number Ranges

+*/

+

+#define TSTIN_VALID_SI3217X_PART_NUM (pProslic->deviceId->chipType >= SI32171 && pProslic->deviceId->chipType <= SI32179)

+#define TSTIN_VALID_SI3218X_PART_NUM (pProslic->deviceId->chipType >= SI32180 && pProslic->deviceId->chipType <= SI32189)

+#define TSTIN_VALID_SI3219X_PART_NUM (pProslic->deviceId->chipType >= SI32190 && pProslic->deviceId->chipType <= SI32199)

+#define TSTIN_VALID_SI3226X_PART_NUM (pProslic->deviceId->chipType >= SI32260 && pProslic->deviceId->chipType <= SI32269)

+#define TSTIN_VALID_SI3228X_PART_NUM (pProslic->deviceId->chipType >= SI32280 && pProslic->deviceId->chipType <= SI32289)

+

+#define TSTIN_INVALID_PART_NUM  !(TSTIN_VALID_SI3217X_PART_NUM ||\

+    TSTIN_VALID_SI3218X_PART_NUM || TSTIN_VALID_SI3219X_PART_NUM ||\

+    TSTIN_VALID_SI3226X_PART_NUM || TSTIN_VALID_SI3228X_PART_NUM)

+

+#define LOGPRINT_PREFIX "ProSLIC:"

+

+ProSLIC_DCfeed_Cfg ringtripTestDCFeedPreset[] =

+{

+  {

+    0x196038D8L,	/* SLOPE_VLIM */

+    0x1D707651L,	/* SLOPE_RFEED */

+    0x0040A0E0L,	/* SLOPE_ILIM */

+    0x1E07FE48L,	/* SLOPE_DELTA1 */

+    0x1ED62D87L,	/* SLOPE_DELTA2 */

+    0x01A50724L,	/* V_VLIM (14.000 v) */

+    0x016EE54FL,	/* V_RFEED (12.200 v) */

+    0x012CBBF5L,	/* V_ILIM  (10.000 v) */

+    0x00AF8C10L,	/* CONST_RFEED (10.000 mA) */

+    0x0045CBBCL,	/* CONST_ILIM (15.000 mA) */

+    0x000D494BL,	/* I_VLIM (0.000 mA) */

+    0x005B0AFBL,	/* LCRONHK (10.000 mA) */

+    0x006D4060L,	/* LCROFFHK (12.000 mA) */

+    0x00008000L,	/* LCRDBI (5.000 ms) */

+    0x0048D595L,	/* LONGHITH (8.000 mA) */

+    0x003FBAE2L,	/* LONGLOTH (7.000 mA) */

+    0x00008000L,	/* LONGDBI (5.000 ms) */

+    0x000F0000L,	/* LCRMASK (150.000 ms) */

+    0x00080000L,	/* LCRMASK_POLREV (80.000 ms) */

+    0x00140000L,	/* LCRMASK_STATE (200.000 ms) */

+    0x00140000L,	/* LCRMASK_LINECAP (200.000 ms) */

+    0x01999999L,	/* VCM_OH (25.000 v) */

+    0x0051EB85L,	/* VOV_BAT (5.000 v) */

+    0x00418937L 	/* VOV_GND (4.000 v) */

+  }

+};

+

+/*

+** dB lookup table

+*/

+#define DB_TABLE_STEP_SIZE     250

+#define MAX_DB_TABLE           279

+

+static const uInt32 dBTable10_n60 [] =

+{

+  31623,

+  30726,

+  29854,

+  29007,

+  28184,

+  27384,

+  26607,

+  25852,

+  25119,

+  24406,

+  23714,

+  23041,

+  22387,

+  21752,

+  21135,

+  20535,

+  19953,

+  19387,

+  18836,

+  18302,

+  17783,

+  17278,

+  16788,

+  16312,

+  15849,

+  15399,

+  14962,

+  14538,

+  14125,

+  13725,

+  13335,

+  12957,

+  12589,

+  12232,

+  11885,

+  11548,

+  11220,

+  10902,

+  10593,

+  10292,

+  10000,

+  9716,

+  9441,

+  9173,

+  8913,

+  8660,

+  8414,

+  8175,

+  7943,

+  7718,

+  7499,

+  7286,

+  7079,

+  6879,

+  6683,

+  6494,

+  6310,

+  6131,

+  5957,

+  5788,

+  5623,

+  5464,

+  5309,

+  5158,

+  5012,

+  4870,

+  4732,

+  4597,

+  4467,

+  4340,

+  4217,

+  4097,

+  3981,

+  3868,

+  3758,

+  3652,

+  3548,

+  3447,

+  3350,

+  3255,

+  3162,

+  3073,

+  2985,

+  2901,

+  2818,

+  2738,

+  2661,

+  2585,

+  2512,

+  2441,

+  2371,

+  2304,

+  2239,

+  2175,

+  2113,

+  2054,

+  1995,

+  1939,

+  1884,

+  1830,

+  1778,

+  1728,

+  1679,

+  1631,

+  1585,

+  1540,

+  1496,

+  1454,

+  1413,

+  1372,

+  1334,

+  1296,

+  1259,

+  1223,

+  1189,

+  1155,

+  1122,

+  1090,

+  1059,

+  1029,

+  1000,

+  972,

+  944,

+  917,

+  891,

+  866,

+  841,

+  818,

+  794,

+  772,

+  750,

+  729,

+  708,

+  688,

+  668,

+  649,

+  631,

+  613,

+  596,

+  579,

+  562,

+  546,

+  531,

+  516,

+  501,

+  487,

+  473,

+  460,

+  447,

+  434,

+  422,

+  410,

+  398,

+  387,

+  376,

+  365,

+  355,

+  345,

+  335,

+  325,

+  316,

+  307,

+  299,

+  290,

+  282,

+  274,

+  266,

+  259,

+  251,

+  244,

+  237,

+  230,

+  224,

+  218,

+  211,

+  205,

+  200,

+  194,

+  188,

+  183,

+  178,

+  173,

+  168,

+  163,

+  158,

+  154,

+  150,

+  145,

+  141,

+  137,

+  133,

+  130,

+  126,

+  122,

+  119,

+  115,

+  112,

+  109,

+  106,

+  103,

+  100,

+  97,

+  94,

+  92,

+  89,

+  87,

+  84,

+  82,

+  79,

+  77,

+  75,

+  73,

+  71,

+  69,

+  67,

+  65,

+  63,

+  61,

+  60,

+  58,

+  56,

+  55,

+  53,

+  52,

+  50,

+  49,

+  47,

+  46,

+  45,

+  43,

+  42,

+  41,

+  40,

+  39,

+  38,

+  37,

+  35,

+  34,

+  33,

+  33,

+  32,

+  31,

+  30,

+  29,

+  28,

+  27,

+  27,

+  26,

+  25,

+  24,

+  24,

+  23,

+  22,

+  22,

+  21,

+  21,

+  20,

+  19,

+  19,

+  18,

+  18,

+  17,

+  17,

+  16,

+  16,

+  15,

+  15,

+  15,

+  14,

+  14,

+  13,

+  13,

+  13,

+  12,

+  12,

+  12,

+  11,

+  11,

+  11,

+  10,

+  10

+};

+

+

+/* *********************************** */

+static int setInternalTestLoad(proslicChanType *pProslic, int connect)

+{

+  ramData ram_save;

+  ramData test_load_addr;

+  ramData test_load_bitmask;

+

+  if(pProslic->deviceId->chipType >= SI32171

+      && pProslic->deviceId->chipType <= SI32179)

+  {

+    test_load_addr = 1516;

+    test_load_bitmask = 0x00800000L;  /* bit 23 */

+  }

+  else

+  {

+    test_load_addr = 1611;

+    test_load_bitmask = 0x00040000L;  /* bit 18 */

+  }

+

+  ProSLIC_SetUserMode(pProslic,1,0);

+  ram_save = ProSLIC_ReadRAM(pProslic,test_load_addr);

+

+  if(connect)

+  {

+    ram_save |= test_load_bitmask;

+  }

+  else

+  {

+    ram_save &= ~test_load_bitmask;

+  }

+

+  ProSLIC_WriteRAM(pProslic,test_load_addr,ram_save);

+

+  return RC_NONE;

+}

+

+/* *********************************** */

+static void setup1kHzBandpass(proslicChanType *pProslic)

+{

+  /* 1kHz bandpass - Gain = -1.7055 */

+  ProSLIC_WriteRAM(pProslic, 32, 0x180A50L);	/* TESTB0_1 */

+  ProSLIC_WriteRAM(pProslic, 33, 0x0L);		/* TESTB1_1 */

+  ProSLIC_WriteRAM(pProslic, 34, 0x1FE7F5B0L);/* TESTB2_1 */

+  ProSLIC_WriteRAM(pProslic, 35, 0xB166220L);	/* TESTA1_1 */

+  ProSLIC_WriteRAM(pProslic, 36, 0x185119D0L);/* TESTA2_1 */

+  ProSLIC_WriteRAM(pProslic, 37, 0xAF624E0L);	/* TESTB0_2 */

+  ProSLIC_WriteRAM(pProslic, 38, 0x0L);		/* TESTB1_2 */

+  ProSLIC_WriteRAM(pProslic, 39, 0xAF624E0L);	/* TESTB2_2 */

+  ProSLIC_WriteRAM(pProslic, 40, 0x0L); 		/* TESTA1_2 */

+  ProSLIC_WriteRAM(pProslic, 41, 0x185119D0L);/* TESTA2_2 */

+  ProSLIC_WriteRAM(pProslic, 42, 0x7C6E410L);	/* TESTB0_3 */

+  ProSLIC_WriteRAM(pProslic, 43, 0xAFF8B80L);	/* TESTB1_3 */

+  ProSLIC_WriteRAM(pProslic, 44, 0x7C6E410L);	/* TESTB2_3 */

+  ProSLIC_WriteRAM(pProslic, 45, 0x14E99DE0L);/* TESTA1_3 */

+  ProSLIC_WriteRAM(pProslic, 46, 0x185119D0L);/* TESTA2_3 */

+  ProSLIC_WriteRAM(pProslic, 50, 0x40000L);	/* TESTAVBW */

+  ProSLIC_WriteRAM(pProslic, 49, 0x1F40000L);	/* TESTWLN */

+  ProSLIC_WriteRAM(pProslic, 54, 0x0L);		/* TESTAVTH */

+  ProSLIC_WriteRAM(pProslic, 53, 0x0L);		/* TESTPKTH */

+}

+

+/* *********************************** */

+/* Return value in dB*1000 (mdB) */

+static int32 dBLookup(uInt32 number)

+{

+  int i;

+  uInt32 err;

+

+  if(number >= dBTable10_n60[0])

+  {

+    return 10000;  /* out of range - clamp at 10dB */

+  }

+

+  for(i=0; i<MAX_DB_TABLE; i++) /* 139 */

+  {

+    if((number < dBTable10_n60[i])&&(number >= dBTable10_n60[i+1]))

+    {

+      /* See which level it is closest to */

+      err = dBTable10_n60[i] - number;

+      if(err < (number - dBTable10_n60[i+1]))

+      {

+        return (10000 - i*DB_TABLE_STEP_SIZE);

+      }

+      else

+      {

+        return (10000 - (i+1)*DB_TABLE_STEP_SIZE);

+      }

+    }

+  }

+  /* No solution found?  Return -60dB */

+  return -60000;

+}

+

+/* *********************************** */

+static int32 readAudioDiagLevel(proslicChanType *pProslic,int32 zero_dbm_mvpk)

+{

+  int32 data;

+

+  data = ProSLIC_ReadRAM(pProslic,47); /* TESTPKO */

+  DEBUG_PRINT(pProslic, "TESTPKO = %d\n", (int)data);

+

+  data /= 40145;         /* 2^28 * 0.182 * 10^(Gfilt/20) */

+  data *= 1000;

+  data /= zero_dbm_mvpk;

+  data *= 10;

+

+  return(dBLookup(data));

+}

+

+/* *********************************** */

+static char *applyTestLimits(proslicTestObj *test)

+{

+  if((test->value >= test->lowerLimit)&&(test->value <= test->upperLimit))

+  {

+    test->testResult = RC_TEST_PASSED;

+    return ("PASS");

+  }

+  else

+  {

+    test->testResult = RC_TEST_FAILED;

+    return ("FAIL");

+  }

+}

+

+

+

+/* *********************************** */

+static int logTest(proslicChanType *pProslic,proslicTestObj *test,

+                   const char *label)

+{

+  char resultStr[10];

+  SIVOICE_STRCPY(resultStr,applyTestLimits(test));

+  DEBUG_PRINT(pProslic, "ProSLIC : TestIn : %-14s = %-8d :: %s\n", label, (int)(test->value),

+             resultStr);

+#ifndef ENABLE_DEBUG

+  SILABS_UNREFERENCED_PARAMETER(pProslic);

+  SILABS_UNREFERENCED_PARAMETER(label);

+#endif

+  return test->testResult;

+

+}

+/* *********************************** */

+static int logStatus(proslicChanType *pProslic, int status,const char *label)

+{

+  DEBUG_PRINT(pProslic, "ProSLIC : TestIn : %-14s = %d\n", label,status);

+#ifndef ENABLE_DEBUG

+  SILABS_UNREFERENCED_PARAMETER(pProslic);

+  SILABS_UNREFERENCED_PARAMETER(label);

+  SILABS_UNREFERENCED_PARAMETER(status);

+#endif

+  return RC_NONE;

+}

+

+/* *********************************** */

+static uInt32 Isqrt32(uInt32 num)

+{

+  uInt32 one,res,op;

+

+  op=num;

+  res=0;

+  one = 1L << 30;

+  while(one > op)

+  {

+    one >>=2;

+  }

+

+  while(one !=0)

+  {

+    if(op >= res + one)

+    {

+      op = op - (res + one);

+      res = res + 2*one;

+    }

+    res >>= 1;

+    one >>= 2;

+  }

+

+  return (res);

+}

+

+

+/* *********************************** */

+static int storeDCFeedPreset(proslicChanType *pProslic,ProSLIC_DCfeed_Cfg *cfg,uInt8 preset)

+{

+  cfg[preset].slope_vlim = ProSLIC_ReadRAM(pProslic,634);

+  cfg[preset].slope_rfeed = ProSLIC_ReadRAM(pProslic,635);

+  cfg[preset].slope_ilim = ProSLIC_ReadRAM(pProslic,636);

+  cfg[preset].delta1 = ProSLIC_ReadRAM(pProslic,638);

+  cfg[preset].delta2 = ProSLIC_ReadRAM(pProslic,639);

+  cfg[preset].v_vlim = ProSLIC_ReadRAM(pProslic,640);

+  cfg[preset].v_rfeed = ProSLIC_ReadRAM(pProslic,641);

+  cfg[preset].v_ilim = ProSLIC_ReadRAM(pProslic,642);

+  cfg[preset].const_rfeed = ProSLIC_ReadRAM(pProslic,643);

+  cfg[preset].const_ilim = ProSLIC_ReadRAM(pProslic,644);

+  cfg[preset].i_vlim = ProSLIC_ReadRAM(pProslic,645);

+  cfg[preset].lcronhk = ProSLIC_ReadRAM(pProslic,853);

+  cfg[preset].lcroffhk = ProSLIC_ReadRAM(pProslic,852);

+  cfg[preset].lcrdbi = ProSLIC_ReadRAM(pProslic,701);

+  cfg[preset].longhith = ProSLIC_ReadRAM(pProslic,858);

+  cfg[preset].longloth = ProSLIC_ReadRAM(pProslic,859);

+  cfg[preset].longdbi = ProSLIC_ReadRAM(pProslic,702);

+  cfg[preset].lcrmask = ProSLIC_ReadRAM(pProslic,854);

+  cfg[preset].lcrmask_polrev = ProSLIC_ReadRAM(pProslic,855);

+  cfg[preset].lcrmask_state = ProSLIC_ReadRAM(pProslic,856);

+  cfg[preset].lcrmask_linecap = ProSLIC_ReadRAM(pProslic,857);

+  cfg[preset].vcm_oh = ProSLIC_ReadRAM(pProslic,748);

+  cfg[preset].vov_bat = ProSLIC_ReadRAM(pProslic,752);

+  cfg[preset].vov_gnd = ProSLIC_ReadRAM(pProslic,751);

+

+  return RC_NONE;

+}

+

+

+/* *********************************** */

+int ProSLIC_createTestInObjs(proslicTestInObjType_ptr *pTstin, uInt32 num_objs)

+{

+#ifndef DISABLE_MALLOC

+  *pTstin = SIVOICE_CALLOC(sizeof(proslicTestInObjType),num_objs);

+

+  if(*pTstin == NULL)

+  {

+#ifdef ENABLE_DEBUG

+    LOGPRINT("%s: %s: failed to allocate memory", LOGPRINT_PREFIX, __FUNCTION__);

+#endif

+    return RC_NO_MEM;

+  }

+

+  return RC_NONE;

+#else

+  SILABS_UNREFERENCED_PARAMETER(pTstin);

+  SILABS_UNREFERENCED_PARAMETER(num_objs);

+  return RC_UNSUPPORTED_FEATURE;

+#endif

+}

+/* *********************************** */

+int ProSLIC_destroyTestInObjs(proslicTestInObjType_ptr *pTstin)

+{

+#ifndef DISABLE_MALLOC

+  SIVOICE_FREE((proslicTestInObjType_ptr) *pTstin);

+  *pTstin = NULL;

+  return RC_NONE;

+#else

+  SILABS_UNREFERENCED_PARAMETER(pTstin);

+  return RC_UNSUPPORTED_FEATURE;

+#endif

+}

+

+/* *********************************** */

+int ProSLIC_testInPCMLpbkEnable(proslicChanType *pProslic,

+                                proslicTestInObjType *pTstin)

+{

+  uInt8 regData;

+

+  /* Valid device check */

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+

+  /* Check if enabled */

+  if(!pTstin->pcmLpbkTest.testEnable)

+  {

+    return RC_TEST_DISABLED;

+  }

+  /* Return if already enabled */

+  if(pTstin->pcmLpbkTest.pcmLpbkEnabled)

+  {

+    return RC_NONE;

+  }

+

+  /* Store PCM Settings */

+  pTstin->pcmLpbkTest.pcmModeSave = ProSLIC_ReadReg(pProslic,11); /* PCMMODE */

+

+

+  /* Disable PCM bus before changing format */

+  regData = pTstin->pcmLpbkTest.pcmModeSave & ~0x10; /* PCM_EN = 0 */

+  ProSLIC_WriteReg(pProslic,11,regData);

+

+  /* Configure for either 8 or 16bit linear */

+  if(pTstin->pcmLpbkTest.pcm8BitLinear == PCM_8BIT)

+  {

+    regData |= 0x02;   /* PCM_FMT[1] = 1 */

+    regData &= ~0x01;  /* PCM_FMT[0] = 0 */

+  }

+  else /* PCM_16BIT */

+  {

+    regData |= 0x03;  /* PCM_FMT[1:0] = 11 */

+  }

+

+  ProSLIC_WriteReg(pProslic,11,regData);

+

+  /* Enable PCM Loopback */

+  ProSLIC_WriteReg(pProslic,43,0x01);  /* LOOPBACK */

+

+  /* Re-enable PCM Bus */

+  ProSLIC_WriteReg(pProslic,11,regData|0x10);  /* PCMMODE */

+

+  pTstin->pcmLpbkTest.pcmLpbkEnabled = 1;

+  DEBUG_PRINT(pProslic, "ProSLIC : TestIn : pcmLpbk : ENABLED\n");

+  return RC_NONE;

+}

+

+/* *********************************** */

+int ProSLIC_testInPCMLpbkDisable(proslicChanType *pProslic,

+                                 proslicTestInObjType *pTstin)

+{

+  uInt8 regData;

+

+  /* Valid device check */

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+

+  /* Check if enabled */

+  if(!pTstin->pcmLpbkTest.testEnable)

+  {

+    return RC_TEST_DISABLED;

+  }

+

+  /* Return if already disabled */

+  if(!pTstin->pcmLpbkTest.pcmLpbkEnabled)

+  {

+    return RC_NONE;

+  }

+

+  /* Disable PCM Bus */

+  regData = ProSLIC_ReadReg(pProslic,11); /* PCMMODE */

+  ProSLIC_WriteReg(pProslic,11,regData &= ~0x10);

+

+  /* Disable PCM Loopback */

+  ProSLIC_WriteReg(pProslic,43,0);

+

+  /* Restore PCMMODE. Force disabled while changing format */

+  ProSLIC_WriteReg(pProslic,11,pTstin->pcmLpbkTest.pcmModeSave &= ~0x10);

+  ProSLIC_WriteReg(pProslic,11,pTstin->pcmLpbkTest.pcmModeSave);

+

+  pTstin->pcmLpbkTest.pcmLpbkEnabled = 0;

+  DEBUG_PRINT(pProslic, "ProSLIC : TestIn : pcmLpbk : DISABLED\n");

+  return RC_NONE;

+}

+

+/* *************************************************** */

+

+int ProSLIC_testInDCFeed(proslicChanType *pProslic,

+                         proslicTestInObjType *pTstin)

+{

+  uInt8 enhanceRegSave;

+  proslicMonitorType monitor;

+  ramData lcroffhk_save = 0;

+  ramData lcronhk_save = 0;

+

+  /* Valid device check */

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+

+  /* Check if enabled */

+  if(!pTstin->dcFeedTest.testEnable)

+  {

+    return RC_TEST_DISABLED;

+  }

+

+  /* Invalidate last test results */

+  pTstin->dcFeedTest.testDataValid = TSTIN_RESULTS_INVALID;

+

+  /* Verify line not in use */

+  if(ProSLIC_ReadReg(pProslic,34) & 0x02)  /* LCR */

+  {

+    DEBUG_PRINT(pProslic, "\nProSLIC : TestIn : DC Feed : Line in Use\n");

+

+    if(pTstin->dcFeedTest.abortIfLineInUse==ABORT_LIU_ENABLED)

+    {

+      return RC_LINE_IN_USE;

+    }

+  }

+

+  /* Disable Powersave */

+  enhanceRegSave = ProSLIC_ReadReg(pProslic,47);

+  ProSLIC_WriteReg(pProslic,47,0x20);

+  Delay(pProTimer,10);

+

+  /* Onhook measurement */

+  ProSLIC_LineMonitor(pProslic,&monitor);

+

+  pTstin->dcFeedTest.dcfeedVtipOnhook.value = monitor.vtip;

+  pTstin->dcFeedTest.dcfeedVringOnhook.value = monitor.vring;

+  pTstin->dcFeedTest.dcfeedVloopOnhook.value = monitor.vtr;

+  pTstin->dcFeedTest.dcfeedVbatOnhook.value = monitor.vbat;

+  pTstin->dcFeedTest.dcfeedItipOnhook.value = monitor.itip;

+  pTstin->dcFeedTest.dcfeedIringOnhook.value = monitor.iring;

+  pTstin->dcFeedTest.dcfeedIloopOnhook.value = monitor.itr;

+  pTstin->dcFeedTest.dcfeedIlongOnhook.value = monitor.ilong;

+

+  /* Modify LCR threshold (optional) before connecting test load */

+  if(pTstin->dcFeedTest.applyLcrThresh == LCR_CHECK_ENABLED)

+  {

+    lcroffhk_save = ProSLIC_ReadRAM(pProslic,852);

+    lcronhk_save = ProSLIC_ReadRAM(pProslic,853);

+    ProSLIC_WriteRAM(pProslic,852,pTstin->dcFeedTest.altLcrOffThresh);

+    ProSLIC_WriteRAM(pProslic,853,pTstin->dcFeedTest.altLcrOnThresh);

+  }

+

+  /* Connect internal test load for 2nd dc feed i/v point */

+  setInternalTestLoad(pProslic,1);

+  Delay(pProTimer,50);

+  /* Offhook measurement */

+  ProSLIC_LineMonitor(pProslic,&monitor);

+

+  pTstin->dcFeedTest.dcfeedVtipOffhook.value = monitor.vtip;

+  pTstin->dcFeedTest.dcfeedVringOffhook.value = monitor.vring;

+  pTstin->dcFeedTest.dcfeedVloopOffhook.value = monitor.vtr;

+  pTstin->dcFeedTest.dcfeedVbatOffhook.value = monitor.vbat;

+  pTstin->dcFeedTest.dcfeedItipOffhook.value = monitor.itip;

+  pTstin->dcFeedTest.dcfeedIringOffhook.value = monitor.iring;

+  pTstin->dcFeedTest.dcfeedIloopOffhook.value = monitor.itr;

+  pTstin->dcFeedTest.dcfeedIlongOffhook.value = monitor.ilong;

+

+  pTstin->dcFeedTest.testResult = RC_TEST_PASSED;  /* initialize */

+  /* Read LCR */

+  if(ProSLIC_ReadReg(pProslic,34) & 0x07)  /* LCRRTP */

+  {

+    pTstin->dcFeedTest.lcrStatus = 1;

+  }

+  else

+  {

+    pTstin->dcFeedTest.lcrStatus = 0;

+  }

+

+  /* Only fail check if enabled */

+  if(pTstin->dcFeedTest.applyLcrThresh == LCR_CHECK_ENABLED)

+  {

+    pTstin->dcFeedTest.testResult |= !pTstin->dcFeedTest.lcrStatus;

+  }

+

+  /* Disconnect Test Load */

+  setInternalTestLoad(pProslic,0);

+

+  /* Restore LCR thresholds */

+  if(pTstin->dcFeedTest.applyLcrThresh == LCR_CHECK_ENABLED)

+  {

+    ProSLIC_WriteRAM(pProslic,852,lcroffhk_save);

+    ProSLIC_WriteRAM(pProslic,853,lcronhk_save);

+  }

+

+  /* Restore enhance reg */

+  ProSLIC_WriteReg(pProslic,47,enhanceRegSave);

+

+  /* Process Results */

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVtipOnhook),"DcFeed : Vtip Onhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVringOnhook),"DcFeed : Vring Onhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVloopOnhook),"DcFeed : Vloop Onhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVbatOnhook),"DcFeed : Vbat Onhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedItipOnhook),"DcFeed : Itip Onhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedIringOnhook),"DcFeed : Iring Onhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedIloopOnhook),"DcFeed : Iloop Onhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedIlongOnhook),"DcFeed : Ilong Onhook");

+

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVtipOffhook),"DcFeed : Vtip Offhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVringOffhook),"DcFeed : Vring Offhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVloopOffhook),"DcFeed : Vloop Offhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedVbatOffhook),"DcFeed : Vbat Offhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedItipOffhook),"DcFeed : Itip Offhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedIringOffhook),"DcFeed : Iring Offhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedIloopOffhook),"DcFeed : Iloop Offhook");

+  pTstin->dcFeedTest.testResult |= logTest(pProslic,

+                                   &(pTstin->dcFeedTest.dcfeedIlongOffhook),"DcFeed : Ilong Offhook");

+

+  logStatus(pProslic,pTstin->dcFeedTest.lcrStatus,"DcFeed : LCR");

+

+

+  pTstin->dcFeedTest.testDataValid = 1;   /* New valid results */

+

+  /* return cumulative pass/fail result */

+

+  return (pTstin->dcFeedTest.testResult);

+}

+

+/* *********************************** */

+int ProSLIC_testInRinging(proslicChanType *pProslic,

+                          proslicTestInObjType *pTstin)

+{

+  uInt8 ringcon_save,enhance_save;

+  int32 vtr[MAX_RINGING_SAMPLES];

+  int i;

+  uInt8 lf;

+  uInt32 rtper_save, ringfr_save,ringamp_save,ringof_save,rtacth_save,rtdcth_save;

+  ProSLIC_DCfeed_Cfg dcfeedCfg[1];

+

+  /* Valid device check */

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+

+  /* Check if enabled */

+  if( (!pTstin->ringingTest.testEnable)

+      || (pTstin->ringingTest.numSamples == 0) )

+  {

+    return RC_TEST_DISABLED;

+  }

+

+  /* Verify line not in use */

+  if(ProSLIC_ReadReg(pProslic,34) & 0x02)  /* LCR */

+  {

+    DEBUG_PRINT(pProslic, "\nProSLIC : TestIn : Ringing : Line in Use\n");

+

+    if(pTstin->ringingTest.abortIfLineInUse)

+    {

+      return RC_LINE_IN_USE;

+    }

+  }

+

+  /* Invalidate last test results */

+  pTstin->ringingTest.testDataValid = TSTIN_RESULTS_INVALID;

+

+  /* Check sample size/rate */

+  if(pTstin->ringingTest.numSamples > MAX_RINGING_SAMPLES)

+  {

+    pTstin->ringingTest.numSamples = MAX_RINGING_SAMPLES;

+  }

+

+  if(pTstin->ringingTest.sampleInterval > MAX_RINGING_SAMPLE_INTERVAL)

+  {

+    pTstin->ringingTest.sampleInterval = MAX_RINGING_SAMPLE_INTERVAL;

+  }

+

+  if(pTstin->ringingTest.sampleInterval < MIN_RINGING_SAMPLE_INTERVAL)

+  {

+    pTstin->ringingTest.sampleInterval = MIN_RINGING_SAMPLE_INTERVAL;

+  }

+

+  /* Disable Powersave */

+  enhance_save = ProSLIC_ReadReg(pProslic,47);

+  ProSLIC_WriteReg(pProslic,47,0x20);

+  Delay(pProTimer,10);

+

+  /* Disable ring cadencing */

+  ringcon_save = ProSLIC_ReadReg(pProslic,38); /* RINGCON */

+  ProSLIC_WriteReg(pProslic,38,ringcon_save&0xE7); /* RINGCON */

+

+  /* Must enter ringing through active state */

+  lf = ProSLIC_ReadReg(pProslic,30);  /* LINEFEED */

+  ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+  Delay(pProTimer,20); /* settle */

+

+  /* Start ringing */

+  ProSLIC_SetLinefeedStatus(pProslic,LF_RINGING);

+  Delay(pProTimer,500);

+

+  /* Verify Ring Started */

+  if(ProSLIC_ReadReg(pProslic,30) != 0x44)

+  {

+    ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+    ProSLIC_SetLinefeedStatus(pProslic,LF_OPEN);

+    ProSLIC_WriteReg(pProslic,38,ringcon_save);

+    ProSLIC_WriteReg(pProslic,47,enhance_save);

+    ProSLIC_SetLinefeedStatus(pProslic,lf);

+    

+    DEBUG_PRINT(pProslic, "ProSLIC : TestIn : Ringing : Ring Start Fail\n");

+

+    pTstin->ringingTest.testResult = RC_TEST_FAILED;

+    return RC_RING_START_FAIL;

+  }

+

+  /* Capture samples */

+  pTstin->ringingTest.ringingVdc.value = 0;

+  for(i=0; i<pTstin->ringingTest.numSamples; i++)

+  {

+    vtr[i] = ProSLIC_ReadMADCScaled(pProslic,69,0); /* VDIFF_FILT */

+    pTstin->ringingTest.ringingVdc.value += vtr[i];

+

+    DEBUG_PRINT(pProslic, "ProSLIC : TestIn : Ringing : Vtr[%d] = %d\n",i, (int)(vtr[i]));

+

+    Delay(pProTimer,pTstin->ringingTest.sampleInterval);

+  }

+

+  /* Restore linefeed */

+  ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+  Delay(pProTimer,20);

+

+  /* Process Results */

+  pTstin->ringingTest.ringingVdc.value /= pTstin->ringingTest.numSamples;

+  for(i=0; i<pTstin->ringingTest.numSamples; i++)

+  {

+    vtr[i] -= pTstin->ringingTest.ringingVdc.value;

+    pTstin->ringingTest.ringingVac.value += ((vtr[i]/100L) * (vtr[i]/100L));

+  }

+

+

+  pTstin->ringingTest.ringingVac.value /= pTstin->ringingTest.numSamples;

+  pTstin->ringingTest.ringingVac.value = Isqrt32(

+      pTstin->ringingTest.ringingVac.value);

+  pTstin->ringingTest.ringingVac.value *= 100L;

+

+  pTstin->ringingTest.testResult = RC_TEST_PASSED;

+  pTstin->ringingTest.testResult |= logTest(pProslic,

+                                    &(pTstin->ringingTest.ringingVdc),"Ringing : VDC");

+  pTstin->ringingTest.testResult |= logTest(pProslic,

+                                    &(pTstin->ringingTest.ringingVac),"Ringing : VAC");

+  /*

+  ** Optional Ringtrip Test

+  */

+

+  if(pTstin->ringingTest.ringtripTestEnable == RTP_CHECK_ENABLED)

+  {

+    /* Setup low voltage linefeed so low level ringing may be used */

+    ProSLIC_SetLinefeedStatus(pProslic,LF_OPEN);

+    storeDCFeedPreset(pProslic,&(dcfeedCfg[0]),0);

+    ProSLIC_DCFeedSetupCfg(pProslic,&(ringtripTestDCFeedPreset[0]),0);

+

+    /* Optional Ringtrip Test (modified ringer settings to use test load to trip) */

+    rtper_save = ProSLIC_ReadRAM(pProslic,755);

+    ringfr_save = ProSLIC_ReadRAM(pProslic,844);

+    ringamp_save = ProSLIC_ReadRAM(pProslic,845);

+    ringof_save = ProSLIC_ReadRAM(pProslic,843);

+    rtacth_save = ProSLIC_ReadRAM(pProslic,848);

+    rtdcth_save = ProSLIC_ReadRAM(pProslic,847);

+

+    ProSLIC_WriteRAM(pProslic,755,0x50000L);  /* RTPER */

+    ProSLIC_WriteRAM(pProslic,844,0x7EFE000L);/* RINGFR */

+    ProSLIC_WriteRAM(pProslic,845,0xD6307L);  /* RINGAMP */

+    ProSLIC_WriteRAM(pProslic,843,0x0L);      /* RINGOF */

+    ProSLIC_WriteRAM(pProslic,848,0x7827FL);  /* RTACTH */

+    ProSLIC_WriteRAM(pProslic,847,0xFFFFFFFL);/* RTDCTH */

+

+    /* Start ringing from active state */

+    ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+    Delay(pProTimer,20);

+    ProSLIC_SetLinefeedStatus(pProslic,LF_RINGING);

+    Delay(pProTimer,200);

+

+    /* Verify Ring Started */

+    if(ProSLIC_ReadReg(pProslic,30) != 0x44)

+    {

+      ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+      ProSLIC_SetLinefeedStatus(pProslic,LF_OPEN);

+      ProSLIC_WriteReg(pProslic,38,ringcon_save);

+      ProSLIC_WriteReg(pProslic,47,enhance_save);

+      

+      /* Restore DC Feed */

+      ProSLIC_DCFeedSetupCfg(pProslic,&(dcfeedCfg[0]),0);

+

+      /* Restore Ring Settings */

+      ProSLIC_WriteRAM(pProslic,755,rtper_save); /* RTPER */

+      ProSLIC_WriteRAM(pProslic,844,ringfr_save); /*RINGFR */

+      ProSLIC_WriteRAM(pProslic,845,ringamp_save); /* RINGAMP */

+      ProSLIC_WriteRAM(pProslic,843,ringof_save); /* RINGOF */

+      ProSLIC_WriteRAM(pProslic,848,rtacth_save); /* RTACTH */

+      ProSLIC_WriteRAM(pProslic,847,rtdcth_save); /* RTDCTH */

+      

+      ProSLIC_SetLinefeedStatus(pProslic,lf);

+

+      DEBUG_PRINT(pProslic, "ProSLIC : TestIn : Ringtrip : Ring Start Fail\n");

+

+      pTstin->ringingTest.testResult=RC_TEST_FAILED;

+      return RC_RING_START_FAIL;

+    }

+

+    /* Connect Test Load to cause ringtrip */

+    setInternalTestLoad(pProslic,1);

+    Delay(pProTimer,200);

+

+    /* Check for RTP */

+    if(ProSLIC_ReadReg(pProslic,34) & 0x01)  /* LCRRTP */

+    {

+      pTstin->ringingTest.rtpStatus = 1;

+      pTstin->ringingTest.testResult |= RC_TEST_PASSED;

+    }

+    else

+    {

+      pTstin->ringingTest.rtpStatus = 0;

+      pTstin->ringingTest.testResult |= RC_TEST_FAILED;

+      ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+    }

+    setInternalTestLoad(pProslic,0);

+    Delay(pProTimer,20);

+

+    logStatus(pProslic,pTstin->ringingTest.rtpStatus,"Ringing : RTP");

+

+    /* Restore DC Feed */

+    ProSLIC_DCFeedSetupCfg(pProslic,&(dcfeedCfg[0]),0);

+

+    /* Restore Ring Settings */

+    ProSLIC_WriteRAM(pProslic,755,rtper_save);/* RTPER */

+    ProSLIC_WriteRAM(pProslic,844,ringfr_save);/*RINGFR */

+    ProSLIC_WriteRAM(pProslic,845,ringamp_save); /* RINGAMP */

+    ProSLIC_WriteRAM(pProslic,843,ringof_save); /* RINGOF */

+    ProSLIC_WriteRAM(pProslic,848,rtacth_save);/* RTACTH */

+    ProSLIC_WriteRAM(pProslic,847,rtdcth_save);/* RTDCTH */

+

+  }/* end of ringtrip test  */

+

+  /* Restore Linefeed */

+  ProSLIC_SetLinefeedStatus(pProslic,lf);

+

+  /* Restore RINGCON and ENHANCE */

+  ProSLIC_WriteReg(pProslic,38,ringcon_save);

+  ProSLIC_WriteReg(pProslic,47,enhance_save);

+

+  pTstin->ringingTest.testDataValid = TSTIN_RESULTS_VALID;

+

+  return (pTstin->ringingTest.testResult);

+}

+

+/* *********************************** */

+int ProSLIC_testInBattery(proslicChanType *pProslic,

+                          proslicTestInObjType *pTstin)

+{

+  proslicMonitorType monitor;

+

+  /* Valid device check */

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+

+  /* Check if enabled */

+  if(!pTstin->batteryTest.testEnable)

+  {

+    return RC_TEST_DISABLED;

+  }

+

+  /* Invalidate last test results */

+  pTstin->batteryTest.testDataValid = TSTIN_RESULTS_INVALID;

+

+  /* Measure Battery */

+  ProSLIC_LineMonitor(pProslic,&monitor);

+

+  pTstin->batteryTest.vbat.value = monitor.vbat;

+

+  pTstin->batteryTest.testResult = logTest(pProslic,&(pTstin->batteryTest.vbat),

+                                   "Battery : VBAT");

+

+  pTstin->batteryTest.testDataValid =

+    TSTIN_RESULTS_VALID;   /* New valid results */

+

+  return (pTstin->batteryTest.testResult);

+}

+

+/* *********************************** */

+int ProSLIC_testInAudio(proslicChanType *pProslic, proslicTestInObjType *pTstin)

+{

+  uInt8 enhanceRegSave;

+  uInt8 lf;

+  int32 data;

+  int32 gainMeas1,gainMeas2;

+  int32 gainMeas3 = 0;

+  ProSLIC_audioGain_Cfg gainCfg;

+  int32 Pin = -3980;   /* -10dBm + 6.02dB (since OHT w/ no AC load) */

+

+  /* Valid device check */

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+

+  /* Check if enabled */

+  if(!pTstin->audioTest.testEnable)

+  {

+    return RC_TEST_DISABLED;

+  }

+

+  /* Invalidate last test results */

+  pTstin->audioTest.testDataValid = TSTIN_RESULTS_INVALID;

+

+  /* Verify line not in use */

+  if(ProSLIC_ReadReg(pProslic,34) & 0x02)  /* LCR */

+  {

+    DEBUG_PRINT(pProslic, "\nProSLIC : TestIn : Audio : Line in Use\n");

+

+    if(pTstin->audioTest.abortIfLineInUse == ABORT_LIU_ENABLED)

+    {

+      return RC_LINE_IN_USE;

+    }

+  }

+

+  /* Disable Powersave */

+  enhanceRegSave = ProSLIC_ReadReg(pProslic,47);

+  ProSLIC_WriteReg(pProslic,47,0x20);

+  Delay(pProTimer,10);

+

+

+  /* Setup Audio Filter, enable audio in OHT */

+  lf = ProSLIC_ReadReg(pProslic,30);  /* LINEFEED */

+  ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+  Delay(pProTimer,20); /* settle */

+  setup1kHzBandpass(pProslic);

+  ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_OHT);

+

+  /* Setup osc1 for 1kHz -10dBm tone, disable hybrid, enable filters */

+  ProSLIC_WriteRAM(pProslic,26,0x5A80000L); /* OSC1FREQ */

+  ProSLIC_WriteRAM(pProslic,27,0x5D8000L);  /* OSC1AMP */

+  ProSLIC_WriteReg(pProslic,48,0x02);       /* OMODE */

+  ProSLIC_WriteReg(pProslic,49,0x01);       /* OCON */

+  ProSLIC_WriteReg(pProslic,44,0x10);       /* DIGCON */

+  ProSLIC_WriteReg(pProslic,71,0x10);       /* DIAG1 */

+

+  /* Settle */

+  Delay(pProTimer,800);

+

+  /* Read first gain measurement (Gtx + Grx + Gzadj) */

+  gainMeas1 = readAudioDiagLevel(pProslic,pTstin->audioTest.zerodBm_mVpk);

+

+  /* Bypass TXACHPF and set TXACEQ to unity */

+  gainCfg.acgain = ProSLIC_ReadRAM(pProslic,544);  /* TXACGAIN */

+  gainCfg.aceq_c0 = ProSLIC_ReadRAM(pProslic,540); /* TXACEQ_C0 */

+  gainCfg.aceq_c1 = ProSLIC_ReadRAM(pProslic,541); /* TXACEQ_C1 */

+  gainCfg.aceq_c2 = ProSLIC_ReadRAM(pProslic,542); /* TXACEQ_C2 */

+  gainCfg.aceq_c3 = ProSLIC_ReadRAM(pProslic,543); /* TXACEQ_C3 */

+  ProSLIC_WriteRAM(pProslic,544,0x8000000L);

+  ProSLIC_WriteRAM(pProslic,543,0x0L);

+  ProSLIC_WriteRAM(pProslic,542,0x0L);

+  ProSLIC_WriteRAM(pProslic,541,0x0L);

+  ProSLIC_WriteRAM(pProslic,540,0x8000000L);

+  ProSLIC_WriteReg(pProslic,44,0x18);

+

+  /* Settle */

+  Delay(pProTimer,800);

+

+  /* Read second level measurement (RX level only) */

+  gainMeas2 = readAudioDiagLevel(pProslic,pTstin->audioTest.zerodBm_mVpk);

+

+  /* Adjust txgain if TXACGAIN wasn't unity during gainMeas1 */

+  if(gainCfg.acgain != 0x8000000L)

+  {

+    data = (gainCfg.acgain*10)/134217;

+    gainMeas3 = dBLookup(data);

+  }

+

+  /* Computations */

+  pTstin->audioTest.rxGain.value = gainMeas2 - Pin;

+  pTstin->audioTest.txGain.value = gainMeas1 - gainMeas2 + gainMeas3;

+

+#ifdef ENABLE_DEBUG

+  if( DEBUG_ENABLED(pProslic) )

+  {

+    LOGPRINT("ProSLIC : TestIn : Audio : gainMeas1 = %d\n", (int)gainMeas1);

+    LOGPRINT("ProSLIC : TestIn : Audio : gainMeas2 = %d\n", (int)gainMeas2);

+    LOGPRINT("ProSLIC : TestIn : Audio : gainMeas3 = %d\n", (int)gainMeas3);

+  }

+#endif

+  pTstin->audioTest.testResult = RC_TEST_PASSED;

+  pTstin->audioTest.testResult |= logTest(pProslic,&(pTstin->audioTest.rxGain),

+                                          "RX Path Gain");

+  pTstin->audioTest.testResult |= logTest(pProslic,&(pTstin->audioTest.txGain),

+                                          "TX Path Gain");

+

+

+

+  /*

+  ** Restore

+  */

+

+  /* Need to store/restore all modified reg/RAM */

+  ProSLIC_WriteRAM(pProslic,544,gainCfg.acgain);

+  ProSLIC_WriteRAM(pProslic,540,gainCfg.aceq_c0);

+  ProSLIC_WriteRAM(pProslic,541,gainCfg.aceq_c1);

+  ProSLIC_WriteRAM(pProslic,542,gainCfg.aceq_c2);

+  ProSLIC_WriteRAM(pProslic,543,gainCfg.aceq_c3);

+

+  ProSLIC_WriteReg(pProslic,71,0x0);  /* DIAG1 */

+  ProSLIC_WriteReg(pProslic,44,0x0);  /* DIGCON */

+  ProSLIC_WriteReg(pProslic,48,0x0);  /* OMODE */

+  ProSLIC_WriteReg(pProslic,49,0x0);  /* OCON */

+  ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+  ProSLIC_WriteReg(pProslic,47,enhanceRegSave);

+  ProSLIC_SetLinefeedStatus(pProslic,lf);

+

+  /* Validate last test results */

+  pTstin->audioTest.testDataValid = TSTIN_RESULTS_VALID;

+

+  return pTstin->audioTest.testResult;

+}

+

+

+/* *********************************** */

+

+int ProSLIC_testInPcmLpbkSetup(proslicTestInObjType *pTstin,

+                               proslicPcmLpbkTest *pcmLpbkTest)

+{

+  pTstin->pcmLpbkTest = *pcmLpbkTest;

+  pTstin->pcmLpbkTest.testEnable = 1;

+

+  return RC_NONE;

+}

+

+/* *********************************** */

+

+int ProSLIC_testInDcFeedSetup(proslicTestInObjType *pTstin,

+                              proslicDcFeedTest *dcFeedTest)

+{

+  pTstin->dcFeedTest = *dcFeedTest;

+  pTstin->dcFeedTest.testEnable = 1;

+

+  return RC_NONE;

+}

+

+/* *********************************** */

+

+int ProSLIC_testInRingingSetup(proslicTestInObjType *pTstin,

+                               proslicRingingTest *ringingTest)

+{

+  /* Copy limits per-channel */

+

+  pTstin->ringingTest = *ringingTest;

+  pTstin->ringingTest.testEnable = 1;

+

+  return RC_NONE;

+}

+/* *********************************** */

+

+int ProSLIC_testInBatterySetup(proslicTestInObjType *pTstin,

+                               proslicBatteryTest *batteryTest)

+{

+  /* Copy limits per-channel */

+

+  pTstin->batteryTest = *batteryTest;

+  pTstin->batteryTest.testEnable = 1;

+

+  return RC_NONE;

+}

+

+/* *********************************** */

+

+int ProSLIC_testInAudioSetup(proslicTestInObjType *pTstin,

+                             proslicAudioTest *audioTest)

+{

+  /* Copy limits per-channel */

+

+  pTstin->audioTest = *audioTest;

+  pTstin->audioTest.testEnable = 1;

+

+  return RC_NONE;

+}

+

+

+/* *********************************** */

+int ProSLIC_testInPrintLimits(proslicChanType *pProslic,

+                              proslicTestInObjType *pTstin)

+{

+  /* Valid device check */

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+#ifdef ENABLE_DEBUG

+  if( DEBUG_ENABLED(pProslic ) )

+  {

+    LOGPRINT("\n");

+    LOGPRINT("************   Test-In Test Limits **************\n");

+    LOGPRINT("----------------------------------------------------------------\n");

+    LOGPRINT("ProSLIC : Test-In : Limits : vtip_on_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVtipOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vtip_on_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVtipOnhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vring_on_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVringOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vring_on_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVringOnhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vloop_on_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVloopOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vloop_on_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVloopOnhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vbat_on_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVbatOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vbat_on_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVbatOnhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : itip_on_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedItipOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : itip_on_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedItipOnhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iring_on_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIringOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iring_on_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIringOnhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iloop_on_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIloopOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iloop_on_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIloopOnhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : ilong_on_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIlongOnhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : ilong_on_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIlongOnhook.upperLimit));

+    LOGPRINT("----------------------------------------------------------------\n");

+    LOGPRINT("ProSLIC : Test-In : Limits : vtip_off_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVtipOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vtip_off_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVtipOffhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vring_off_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVringOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vring_off_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVringOffhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vloop_off_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVloopOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vloop_off_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVloopOffhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vbat_off_min (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVbatOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : vbat_off_max (mv) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedVbatOffhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : itip_off_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedItipOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : itip_off_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedItipOffhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iring_off_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIringOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iring_off_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIringOffhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iloop_off_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIloopOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : iloop_off_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIloopOffhook.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : ilong_off_min (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIlongOffhook.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : ilong_off_max (ua) = %d\n",

+             (int)(pTstin->dcFeedTest.dcfeedIlongOffhook.upperLimit));

+    LOGPRINT("----------------------------------------------------------------\n");

+    LOGPRINT("ProSLIC : Test-In : Limits : ringing_vac_min (mv) = %d\n",

+             (int)(pTstin->ringingTest.ringingVac.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : ringing_vac_max (mv) = %d\n",

+             (int)(pTstin->ringingTest.ringingVac.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : ringing_vdc_min (mv) = %d\n",

+             (int)(pTstin->ringingTest.ringingVdc.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : ringing_vdc_max (mv) = %d\n",

+             (int)(pTstin->ringingTest.ringingVdc.upperLimit));

+    LOGPRINT("----------------------------------------------------------------\n");

+    LOGPRINT("ProSLIC : Test-In : Limits : battery_vbat_min (mv) = %d\n",

+             (int)(pTstin->batteryTest.vbat.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : battery_vbat_max (mv) = %d\n",

+             (int)(pTstin->batteryTest.vbat.upperLimit));

+    LOGPRINT("----------------------------------------------------------------\n");

+    LOGPRINT("ProSLIC : Test-In : Limits : audio_txgain_min (mdB) = %d\n",

+             (int)(pTstin->audioTest.txGain.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : audio_txgain_max (mdB) = %d\n",

+             (int)(pTstin->audioTest.txGain.upperLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : audio_rxgain_min (mdB) = %d\n",

+             (int)(pTstin->audioTest.rxGain.lowerLimit));

+    LOGPRINT("ProSLIC : Test-In : Limits : audio_rxgain_max (mdB) = %d\n",

+             (int)(pTstin->audioTest.rxGain.upperLimit));

+    LOGPRINT("----------------------------------------------------------------\n");

+    LOGPRINT("\n");

+  }

+#else

+  SILABS_UNREFERENCED_PARAMETER(pTstin);

+#endif

+  return RC_NONE;

+}

+

+

+static ProSLIC_DCfeed_Cfg testLoad_DC_Cfg[] =

+{

+  {

+  0x1DC6E1D3L,  /* SLOPE_VLIM */

+  0x1F909679L,   /* SLOPE_RFEED */

+  0x0040A0E0L,   /* SLOPE_ILIM */

+  0x1B8687BBL,  /* SLOPE_DELTA1 */

+  0x1CC4B75DL,  /* SLOPE_DELTA2 */

+  0x05A38633L,   /* V_VLIM (48.000 v) */

+  0x050D2839L,   /* V_RFEED (43.000 v) */

+  0x03FE7F0FL,   /* V_ILIM  (34.000 v) */

+  0x009DAFD9L, /* CONST_RFEED (10.000 mA) */

+  0x0045CBBCL,  /* CONST_ILIM (15.000 mA) */

+  0x002D8D96L,  /* I_VLIM (0.000 mA) */

+  0x005B0AFBL,  /* LCRONHK (10.000 mA) */

+  0x006D4060L,   /* LCROFFHK (12.000 mA) */

+  0x00008000L,   /* LCRDBI (5.000 ms) */

+  0x0048D595L,   /* LONGHITH (8.000 mA) */

+  0x003FBAE2L,  /* LONGLOTH (7.000 mA) */

+  0x00008000L,   /* LONGDBI (5.000 ms) */

+  0x000F0000L,   /* LCRMASK (150.000 ms) */

+  0x00080000L,   /* LCRMASK_POLREV (80.000 ms) */

+  0x00140000L,   /* LCRMASK_STATE (200.000 ms) */

+  0x00140000L,   /* LCRMASK_LINECAP (200.000 ms) */

+  0x01BA5E35L,  /* VCM_OH (27.000 v) */

+  0x0051EB85L,   /* VOV_BAT (5.000 v) */

+  0x00418937L,   /* VOV_GND (4.000 v) */

+  }

+};

+

+/* *********************************** */

+int ProSLIC_testLoadTest(

+  SiVoiceChanType_ptr pProslic, 

+  BOOLEAN is_testStart, 

+  uint32_t timeDelayMsec)

+{

+  static ProSLIC_DCfeed_Cfg dcfeedCfg;

+  static uInt8 digcon_reg_cache;

+

+  TRACEPRINT(pProslic, " channel: %u is_testStart: %u delay = %u",

+    pProslic->channel, 

+    is_testStart,

+    timeOffhookMsec);

+  /* Valid device check */

+

+  if(TSTIN_INVALID_PART_NUM)

+  {

+    return RC_UNSUPPORTED_FEATURE;

+  }

+

+  if( TRUE == is_testStart )

+  {

+    /* Verify line not in use */

+    if(ProSLIC_ReadReg(pProslic,PROSLIC_REG_LCRRTP) & 0x02)  /* LCR */

+    {

+      DEBUG_PRINT(pProslic, "\nLine in Use: %u.\n", pProslic->channel);

+      return RC_LINE_IN_USE;

+    }

+   

+    /* Setup lower ILIM linefeed */

+    ProSLIC_SetLinefeedStatus(pProslic,LF_OPEN);

+    storeDCFeedPreset(pProslic, &dcfeedCfg, 0);

+

+    ProSLIC_DCFeedSetupCfg( pProslic, testLoad_DC_Cfg, 0 ); 

+

+    ProSLIC_SetLinefeedStatus(pProslic,LF_FWD_ACTIVE);

+    Delay(pProTimer,100);

+  

+    /* Connect Test Load to cause LCR interrupt*/

+    setInternalTestLoad(pProslic,1);

+    Delay(pProTimer, timeDelayMsec);

+    DEBUG_PRINT(pProslic, "\n%s: test load on for channel %u\n", 

+      __FUNCTION__, pProslic->channel);

+  

+    /* Disable hybrid circuit for test load loopback */

+    digcon_reg_cache = ProSLIC_ReadReg(pProslic,PROSLIC_REG_DIGCON);

+

+    ProSLIC_WriteReg(pProslic, PROSLIC_REG_DIGCON,

+      digcon_reg_cache |0x10 );

+

+    /* At this point the test load should of caused a LCR interrupt and

+       there is an audio path available. NOTE: there may be some distortion

+       of the audio...

+    */

+    

+  }

+  else

+  {

+    /* Restore hybrid circuit */

+    ProSLIC_WriteReg(pProslic,

+      PROSLIC_REG_DIGCON, digcon_reg_cache );

+ 

+    /* Disconnect Test Load */

+    setInternalTestLoad(pProslic,0);

+    Delay(pProTimer, timeDelayMsec);

+    DEBUG_PRINT(pProslic, "\n%s: test load off for channel %u.\n",

+      __FUNCTION__, pProslic->channel);

+  

+   /* Restore DC Feed */

+   ProSLIC_DCFeedSetupCfg(pProslic, &dcfeedCfg, 0);

+  }

+

+  return RC_NONE;

+}

+

diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si3218x_LCCB_constants.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si3218x_LCCB_constants.c
new file mode 100644
index 0000000..ad948e9
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si3218x_LCCB_constants.c
@@ -0,0 +1,686 @@
+// SPDX-License-Identifier: GPL-2.0

+/*

+ * Si3218x ProSLIC API Configuration Tool Version 4.2.1

+ * Last Updated in API Release: 9.2.0

+ * source XML file: si3218x_LCCB_constants.xml

+ *

+ * Auto generated file from configuration tool.

+ */

+

+

+#include "../inc/proslic.h"

+#include "../inc/si3218x.h"

+

+Si3218x_General_Cfg Si3218x_General_Configuration  = {

+0x72,                       /* DEVICE_KEY */

+BO_DCDC_LCCB,               /* BOM_OPT */

+VDC_4P5_16P0,               /* VDC_RANGE_OPT */

+AUTO_ZCAL_ENABLED,          /* ZCAL_ENABLE */

+BO_STD_BOM,                 /* PM_BOM */

+0x00000000L,                /* DCDC_OITHRESH_LO */

+0x01A00000L,                /* DCDC_OITHRESH_HI */

+0x00A00000L,                /* DCDC_OVTHRESH */

+5000L,                      /* DCDC_UVTHRESH */

+1000L,                      /* DCDC_UVHYST */

+0x00000000L,                /* DCDC_FSW_VTHLO */

+0x00000000L,                /* DCDC_FSW_VHYST */

+0x0048D15BL,                /* P_TH_HVIC */

+0x07FEB800L,                /* COEF_P_HVIC */

+0x00083120L,                /* BAT_HYST */

+0x03D70A20L,                /* VBATH_EXPECT (60.00V) */

+0x06666635L,                /* VBATR_EXPECT (100.00V) */

+0x0FFF0000L,                /* PWRSAVE_TIMER */

+0x01999A00L,                /* OFFHOOK_THRESH */

+0x00F00000L,                /* VBAT_TRACK_MIN */

+0x00F00000L,                /* VBAT_TRACK_MIN_RNG */

+0x0ADD5500L,                /* DCDC_ANA_SCALE */

+0x00800000L,                /* THERM_DBI */

+0x00FFFFFFL,                /* VOV_DCDC_SLOPE */

+0x00A18937L,                /* VOV_DCDC_OS */

+0x00A18937L,                /* VOV_RING_BAT_DCDC */

+0x00E49BA5L,                /* VOV_RING_BAT_MAX */

+0x01018900L,                /* DCDC_VERR */

+0x0080C480L,                /* DCDC_VERR_HYST */

+0x00400000L,                /* PD_UVLO */

+0x00400000L,                /* PD_OVLO */

+0x00200000L,                /* PD_OCLO */

+0x00400000L,                /* PD_SWDRV */

+0x00000000L,                /* DCDC_UVPOL */

+0x00200000L,                /* DCDC_RNGTYPE */

+0x00180000L,                /* DCDC_ANA_TOFF */

+0x00100000L,                /* DCDC_ANA_TONMIN */

+0x012FC000L,                /* DCDC_ANA_TONMAX */

+0x50,                       /* IRQEN1 */

+0x13,                       /* IRQEN2 */

+0x03,                       /* IRQEN3 */

+0x00,                       /* IRQEN4 */

+0x30,                       /* ENHANCE */

+0x3F,                       /* AUTO */

+};

+

+Si3218x_audioGain_Cfg Si3218x_audioGain_Presets [] = {

+{0x1377080L,0, 0x0L, 0x0L, 0x0L, 0x0L},

+{0x80C3180L,0, 0x0L, 0x0L, 0x0L, 0x0L}

+};

+

+Si3218x_Ring_Cfg Si3218x_Ring_Presets[] ={

+{

+/*

+	Loop = 500.0 ft @ 0.044 ohms/ft, REN = 3, Rcpe = 600 ohms

+	Rprot = 54 ohms, Type = LPR, Waveform = SINE

+*/ 

+0x00050000L,	/* RTPER */

+0x07EFE000L,	/* RINGFR (20.000 Hz) */

+0x00209380L,	/* RINGAMP (55.000 vrms)  */

+0x00000000L,	/* RINGPHAS */

+0x00000000L,	/* RINGOF (0.000 vdc) */

+0x15E5200EL,	/* SLOPE_RING (100.000 ohms) */

+0x006C94D6L,	/* IRING_LIM (70.000 mA) */

+0x00522220L,	/* RTACTH (45.357 mA) */

+0x0FFFFFFFL,	/* RTDCTH (450.000 mA) */

+0x00006000L,	/* RTACDB (75.000 ms) */

+0x00006000L,	/* RTDCDB (75.000 ms) */

+0x0051EB82L,	/* VOV_RING_BAT (5.000 v) */

+0x00000000L,	/* VOV_RING_GND (0.000 v) */

+0x05B835EFL,	/* VBATR_EXPECT (89.368 v) */

+0x80,			/* RINGTALO (2.000 s) */

+0x3E,			/* RINGTAHI */

+0x00,			/* RINGTILO (4.000 s) */

+0x7D,			/* RINGTIHI */

+0x00000000L,	/* ADAP_RING_MIN_I */

+0x00003000L,	/* COUNTER_IRING_VAL */

+0x00051EB8L,	/* COUNTER_VTR_VAL */

+0x00000000L,	/* CONST_028 */

+0x00000000L,	/* CONST_032 */

+0x00000000L,	/* CONST_038 */

+0x00000000L,	/* CONST_046 */

+0x00000000L,	/* RRD_DELAY */

+0x00000000L,	/* RRD_DELAY2 */

+0x01893740L,	/* VBAT_TRACK_MIN_RNG */

+0x98,			/* RINGCON */

+0x00,			/* USERSTAT */

+0x02DC1AF7L,	/* VCM_RING (43.434 v) */

+0x02DC1AF7L,	/* VCM_RING_FIXED */

+0x003126E8L,	/* DELTA_VCM */

+0x00200000L,	/* DCDC_RNGTYPE */

+},  /* DEFAULT_RINGING */

+{

+/*

+	Loop = 500.0 ft @ 0.044 ohms/ft, REN = 5, Rcpe = 600 ohms

+	Rprot = 54 ohms, Type = LPR, Waveform = SINE

+*/ 

+0x00050000L,	/* RTPER */

+0x07EFE000L,	/* RINGFR (20.000 Hz) */

+0x001C0AFCL,	/* RINGAMP (45.000 vrms)  */

+0x00000000L,	/* RINGPHAS */

+0x00000000L,	/* RINGOF (0.000 vdc) */

+0x15E5200EL,	/* SLOPE_RING (100.000 ohms) */

+0x006C94D6L,	/* IRING_LIM (70.000 mA) */

+0x0068A9B9L,	/* RTACTH (57.798 mA) */

+0x0FFFFFFFL,	/* RTDCTH (450.000 mA) */

+0x00006000L,	/* RTACDB (75.000 ms) */

+0x00006000L,	/* RTDCDB (75.000 ms) */

+0x0051EB82L,	/* VOV_RING_BAT (5.000 v) */

+0x00000000L,	/* VOV_RING_GND (0.000 v) */

+0x04F7DA57L,	/* VBATR_EXPECT (77.628 v) */

+0x80,			/* RINGTALO (2.000 s) */

+0x3E,			/* RINGTAHI */

+0x00,			/* RINGTILO (4.000 s) */

+0x7D,			/* RINGTIHI */

+0x00000000L,	/* ADAP_RING_MIN_I */

+0x00003000L,	/* COUNTER_IRING_VAL */

+0x00051EB8L,	/* COUNTER_VTR_VAL */

+0x00000000L,	/* CONST_028 */

+0x00000000L,	/* CONST_032 */

+0x00000000L,	/* CONST_038 */

+0x00000000L,	/* CONST_046 */

+0x00000000L,	/* RRD_DELAY */

+0x00000000L,	/* RRD_DELAY2 */

+0x01893740L,	/* VBAT_TRACK_MIN_RNG */

+0x98,			/* RINGCON */

+0x00,			/* USERSTAT */

+0x027BED2BL,	/* VCM_RING (37.564 v) */

+0x027BED2BL,	/* VCM_RING_FIXED */

+0x003126E8L,	/* DELTA_VCM */

+0x00200000L,	/* DCDC_RNGTYPE */

+}   /* RING_F20_45VRMS_0VDC_LPR */

+};

+

+Si3218x_DCfeed_Cfg Si3218x_DCfeed_Presets[] = {

+{

+0x1C8A024CL,	/* SLOPE_VLIM */

+0x1F909679L,	/* SLOPE_RFEED */

+0x0040A0E0L,	/* SLOPE_ILIM */

+0x1D5B21A9L,	/* SLOPE_DELTA1 */

+0x1DD87A3EL,	/* SLOPE_DELTA2 */

+0x05A38633L,	/* V_VLIM (48.000 v) */

+0x050D2839L,	/* V_RFEED (43.000 v) */

+0x03FE7F0FL,	/* V_ILIM  (34.000 v) */

+0x00B4F3C3L,	/* CONST_RFEED (15.000 mA) */

+0x005D0FA6L,	/* CONST_ILIM (20.000 mA) */

+0x002D8D96L,	/* I_VLIM (0.000 mA) */

+0x005B0AFBL,	/* LCRONHK (10.000 mA) */

+0x006D4060L,	/* LCROFFHK (12.000 mA) */

+0x00008000L,	/* LCRDBI (5.000 ms) */

+0x0048D595L,	/* LONGHITH (8.000 mA) */

+0x003FBAE2L,	/* LONGLOTH (7.000 mA) */

+0x00008000L,	/* LONGDBI (5.000 ms) */

+0x000F0000L,	/* LCRMASK (150.000 ms) */

+0x00080000L,	/* LCRMASK_POLREV (80.000 ms) */

+0x00140000L,	/* LCRMASK_STATE (200.000 ms) */

+0x00140000L,	/* LCRMASK_LINECAP (200.000 ms) */

+0x01BA5E35L,	/* VCM_OH (27.000 v) */

+0x0051EB85L,	/* VOV_BAT (5.000 v) */

+0x00418937L,	/* VOV_GND (4.000 v) */

+},  /* DCFEED_48V_20MA */

+{

+0x1C8A024CL,	/* SLOPE_VLIM */

+0x1EE08C11L,	/* SLOPE_RFEED */

+0x0040A0E0L,	/* SLOPE_ILIM */

+0x1C940D71L,	/* SLOPE_DELTA1 */

+0x1DD87A3EL,	/* SLOPE_DELTA2 */

+0x05A38633L,	/* V_VLIM (48.000 v) */

+0x050D2839L,	/* V_RFEED (43.000 v) */

+0x03FE7F0FL,	/* V_ILIM  (34.000 v) */

+0x01241BC9L,	/* CONST_RFEED (15.000 mA) */

+0x0074538FL,	/* CONST_ILIM (25.000 mA) */

+0x002D8D96L,	/* I_VLIM (0.000 mA) */

+0x005B0AFBL,	/* LCRONHK (10.000 mA) */

+0x006D4060L,	/* LCROFFHK (12.000 mA) */

+0x00008000L,	/* LCRDBI (5.000 ms) */

+0x0048D595L,	/* LONGHITH (8.000 mA) */

+0x003FBAE2L,	/* LONGLOTH (7.000 mA) */

+0x00008000L,	/* LONGDBI (5.000 ms) */

+0x000F0000L,	/* LCRMASK (150.000 ms) */

+0x00080000L,	/* LCRMASK_POLREV (80.000 ms) */

+0x00140000L,	/* LCRMASK_STATE (200.000 ms) */

+0x00140000L,	/* LCRMASK_LINECAP (200.000 ms) */

+0x01BA5E35L,	/* VCM_OH (27.000 v) */

+0x0051EB85L,	/* VOV_BAT (5.000 v) */

+0x00418937L,	/* VOV_GND (4.000 v) */

+},  /* DCFEED_48V_25MA */

+{

+0x1E655196L,	/* SLOPE_VLIM */

+0x001904EFL,	/* SLOPE_RFEED */

+0x0040A0E0L,	/* SLOPE_ILIM */

+0x1B4CAD9EL,	/* SLOPE_DELTA1 */

+0x1BB0F47CL,	/* SLOPE_DELTA2 */

+0x05A38633L,	/* V_VLIM (48.000 v) */

+0x043AA4A6L,	/* V_RFEED (36.000 v) */

+0x025977EAL,	/* V_ILIM  (20.000 v) */

+0x0068B19AL,	/* CONST_RFEED (18.000 mA) */

+0x005D0FA6L,	/* CONST_ILIM (20.000 mA) */

+0x002D8D96L,	/* I_VLIM (0.000 mA) */

+0x005B0AFBL,	/* LCRONHK (10.000 mA) */

+0x006D4060L,	/* LCROFFHK (12.000 mA) */

+0x00008000L,	/* LCRDBI (5.000 ms) */

+0x0048D595L,	/* LONGHITH (8.000 mA) */

+0x003FBAE2L,	/* LONGLOTH (7.000 mA) */

+0x00008000L,	/* LONGDBI (5.000 ms) */

+0x000F0000L,	/* LCRMASK (150.000 ms) */

+0x00080000L,	/* LCRMASK_POLREV (80.000 ms) */

+0x00140000L,	/* LCRMASK_STATE (200.000 ms) */

+0x00140000L,	/* LCRMASK_LINECAP (200.000 ms) */

+0x01BA5E35L,	/* VCM_OH (27.000 v) */

+0x0051EB85L,	/* VOV_BAT (5.000 v) */

+0x00418937L,	/* VOV_GND (4.000 v) */

+},  /* DCFEED_PSTN_DET_1 */

+{

+0x1A10433FL,	/* SLOPE_VLIM */

+0x1C206275L,	/* SLOPE_RFEED */

+0x0040A0E0L,	/* SLOPE_ILIM */

+0x1C1F426FL,	/* SLOPE_DELTA1 */

+0x1EB51625L,	/* SLOPE_DELTA2 */

+0x041C91DBL,	/* V_VLIM (35.000 v) */

+0x03E06C43L,	/* V_RFEED (33.000 v) */

+0x038633E0L,	/* V_ILIM  (30.000 v) */

+0x022E5DE5L,	/* CONST_RFEED (10.000 mA) */

+0x005D0FA6L,	/* CONST_ILIM (20.000 mA) */

+0x0021373DL,	/* I_VLIM (0.000 mA) */

+0x005B0AFBL,	/* LCRONHK (10.000 mA) */

+0x006D4060L,	/* LCROFFHK (12.000 mA) */

+0x00008000L,	/* LCRDBI (5.000 ms) */

+0x0048D595L,	/* LONGHITH (8.000 mA) */

+0x003FBAE2L,	/* LONGLOTH (7.000 mA) */

+0x00008000L,	/* LONGDBI (5.000 ms) */

+0x000F0000L,	/* LCRMASK (150.000 ms) */

+0x00080000L,	/* LCRMASK_POLREV (80.000 ms) */

+0x00140000L,	/* LCRMASK_STATE (200.000 ms) */

+0x00140000L,	/* LCRMASK_LINECAP (200.000 ms) */

+0x01BA5E35L,	/* VCM_OH (27.000 v) */

+0x0051EB85L,	/* VOV_BAT (5.000 v) */

+0x00418937L,	/* VOV_GND (4.000 v) */

+}   /* DCFEED_PSTN_DET_2 */

+};

+

+Si3218x_Impedance_Cfg Si3218x_Impedance_Presets[] ={

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=600_0_0 rprot=30 rfuse=24 emi_cap=10*/

+{

+{0x07F3A400L, 0x000FF180L, 0x00009380L, 0x1FFDA800L,    /* TXACEQ */

+ 0x07EF1600L, 0x0014B500L, 0x1FFD6580L, 0x1FFCA400L},   /* RXACEQ */

+{0x0008EF00L, 0x00099780L, 0x017DF600L, 0x0096B900L,    /* ECFIR/ECIIR */

+ 0x02549000L, 0x1E4B7D00L, 0x018EEE00L, 0x1EEE0600L,

+ 0x008A8080L, 0x1F713080L, 0x0489BA00L, 0x03592500L},

+{0x0086CE00L, 0x1EF46980L, 0x0084CB00L, 0x0FE34F00L,    /* ZSYNTH */

+ 0x181CA780L, 0x5D}, 

+ 0x08EB8E00L,   /* TXACGAIN */

+ 0x01532100L,   /* RXACGAIN */

+ 0x07AA7180L, 0x18558F00L, 0x0754E300L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ },  /* ZSYN_600_0_0_30_0 */

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=270_750_150 rprot=30 rfuse=24 emi_cap=10*/

+{

+{0x0750E500L, 0x1FC70280L, 0x000BA980L, 0x1FFD2880L,    /* TXACEQ */

+ 0x0A8E2380L, 0x1B905280L, 0x00847700L, 0x1FDAFA00L},   /* RXACEQ */

+{0x002C8880L, 0x1F630D80L, 0x027F7980L, 0x1F3AD200L,    /* ECFIR/ECIIR */

+ 0x040B8680L, 0x1F414D00L, 0x01427B00L, 0x00208200L,

+ 0x0026AE00L, 0x1FD71680L, 0x0C8EDB00L, 0x1B688A00L},

+{0x1F657980L, 0x0096FE00L, 0x00035500L, 0x0D7FE800L,    /* ZSYNTH */

+ 0x1A7F1A80L, 0xB4}, 

+ 0x08000000L,   /* TXACGAIN */

+ 0x01106B80L,   /* RXACGAIN */

+ 0x07BC8400L, 0x18437C80L, 0x07790880L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ },  /* ZSYN_270_750_150_30_0 */

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=370_620_310 rprot=30 rfuse=24 emi_cap=10*/

+{

+{0x08363C80L, 0x1FB03200L, 0x1FFBD200L, 0x1FFC7A00L,    /* TXACEQ */

+ 0x0A0D0800L, 0x1BEB0880L, 0x1F9DF080L, 0x1FE07F00L},   /* RXACEQ */

+{0x00236380L, 0x1F947D00L, 0x020DE380L, 0x1FBEED00L,    /* ECFIR/ECIIR */

+ 0x03050300L, 0x1F7D1D00L, 0x010A9F80L, 0x00329D80L,

+ 0x003E4100L, 0x1FC0DF00L, 0x0DAADE80L, 0x1A4F2600L},

+{0x00226100L, 0x1F8EEE80L, 0x004E9D00L, 0x0F0B9B00L,    /* ZSYNTH */

+ 0x18F3E580L, 0x99}, 

+ 0x0808D100L,   /* TXACGAIN */

+ 0x0131BE80L,   /* RXACGAIN */

+ 0x07B5C100L, 0x184A3F80L, 0x076B8200L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ },  /* ZSYN_370_620_310_30_0 */

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=220_820_120 rprot=30 rfuse=24 emi_cap=10*/

+{

+{0x07194B80L, 0x1FC63800L, 0x0008D280L, 0x1FFC0600L,    /* TXACEQ */

+ 0x0A849680L, 0x1BB04480L, 0x00A4AA00L, 0x1FD3E680L},   /* RXACEQ */

+{0x001B8C00L, 0x1FC65400L, 0x016A5F00L, 0x01323C80L,    /* ECFIR/ECIIR */

+ 0x01DB4980L, 0x01484700L, 0x00258000L, 0x007E9C80L,

+ 0x0016FF00L, 0x1FE69100L, 0x0CE9A400L, 0x1B0EA980L},

+{0x00B3D800L, 0x1D2F8280L, 0x021C8B00L, 0x0A157F00L,    /* ZSYNTH */

+ 0x1DE99E80L, 0xAD}, 

+ 0x08000000L,   /* TXACGAIN */

+ 0x01084680L,   /* RXACGAIN */

+ 0x07BBFA80L, 0x18440600L, 0x0777F580L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ },  /* ZSYN_220_820_120_30_0 */

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=600_0_0 rprot=30 rfuse=24 emi_cap=10*/

+{

+{0x07F3A400L, 0x000FF180L, 0x00009380L, 0x1FFDA800L,    /* TXACEQ */

+ 0x07EF1600L, 0x0014B500L, 0x1FFD6580L, 0x1FFCA400L},   /* RXACEQ */

+{0x0008EF00L, 0x00099780L, 0x017DF600L, 0x0096B900L,    /* ECFIR/ECIIR */

+ 0x02549000L, 0x1E4B7D00L, 0x018EEE00L, 0x1EEE0600L,

+ 0x008A8080L, 0x1F713080L, 0x0489BA00L, 0x03592500L},

+{0x0086CE00L, 0x1EF46980L, 0x0084CB00L, 0x0FE34F00L,    /* ZSYNTH */

+ 0x181CA780L, 0x5D}, 

+ 0x08EB8E00L,   /* TXACGAIN */

+ 0x01532100L,   /* RXACGAIN */

+ 0x07AA7180L, 0x18558F00L, 0x0754E300L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ },  /* ZSYN_600_0_1000_30_0 */

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=200_680_100 rprot=30 rfuse=24 emi_cap=10*/

+{

+{0x0778B980L, 0x1FB97E00L, 0x00030780L, 0x1FFC2580L,    /* TXACEQ */

+ 0x09CC0780L, 0x1D104400L, 0x0076CB80L, 0x1FDE3D80L},   /* RXACEQ */

+{0x1FF64C00L, 0x00456280L, 0x00BEC500L, 0x014D3E80L,    /* ECFIR/ECIIR */

+ 0x02EB2B00L, 0x1E983B80L, 0x029EE280L, 0x1E7B7400L,

+ 0x00D19A80L, 0x1F293D80L, 0x06116D00L, 0x01D55C00L},

+{0x01241700L, 0x1CB53A80L, 0x02269400L, 0x0A14BA00L,    /* ZSYNTH */

+ 0x1DE9D080L, 0x99}, 

+ 0x08000000L,   /* TXACGAIN */

+ 0x01152480L,   /* RXACGAIN */

+ 0x07B96C00L, 0x18469480L, 0x0772D800L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ },  /* ZSYN_200_680_100_30_0 */

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=220_820_115 rprot=30 rfuse=24 emi_cap=10*/

+{

+{0x070AC700L, 0x1FCC7280L, 0x00098700L, 0x1FFCE080L,    /* TXACEQ */

+ 0x0A6A6400L, 0x1BE48B80L, 0x009F3B80L, 0x1FD56000L},   /* RXACEQ */

+{0x00314700L, 0x1F6C1D80L, 0x02347480L, 0x00158B80L,    /* ECFIR/ECIIR */

+ 0x03173D00L, 0x0058E580L, 0x00A6DA80L, 0x004B0780L,

+ 0x001B1300L, 0x1FE2DE80L, 0x0C313180L, 0x1BB7FE00L},

+{0x1FD95980L, 0x1ECDE680L, 0x0156F600L, 0x0A0C9600L,    /* ZSYNTH */

+ 0x1DEBF080L, 0xB4}, 

+ 0x08000000L,   /* TXACGAIN */

+ 0x01069C80L,   /* RXACGAIN */

+ 0x07BECB80L, 0x18413500L, 0x077D9700L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ },  /* ZSYN_220_820_115_30_0 */

+/* Source: Database file: cwdb.db */

+/* Database information: */

+/* parameters: zref=600_0_0 rprot=30 rfuse=24 emi_cap=0*/

+{

+{0x081A5300L, 0x1FE00A00L, 0x00071580L, 0x1FFE2600L,    /* TXACEQ */

+ 0x07F9A800L, 0x1FFA7D80L, 0x1FF59E80L, 0x1FFF1400L},   /* RXACEQ */

+{0x0052DC80L, 0x1F455780L, 0x0297A080L, 0x0006D980L,    /* ECFIR/ECIIR */

+ 0x0195DC00L, 0x000E1E80L, 0x1FC53680L, 0x00050800L,

+ 0x00233400L, 0x1FE6DC00L, 0x1FCD1E00L, 0x1FD2FE00L},

+{0x007B9C00L, 0x1F296C80L, 0x005BCD00L, 0x09F07F00L,    /* ZSYNTH */

+ 0x1DF35080L, 0x6F}, 

+ 0x08C2DA80L,   /* TXACGAIN */

+ 0x01495A80L,   /* RXACGAIN */

+ 0x07BECC80L, 0x18413400L, 0x077D9900L,    /* RXACHPF */

+#ifdef ENABLE_HIRES_GAIN

+ 0, 0  /* TXGAIN*10, RXGAIN*10 (hi_res) */

+#else

+ 0, 0  /* TXGAIN, RXGAIN */

+#endif

+ }   /* WB_ZSYN_600_0_0_20_0 */

+};

+

+Si3218x_FSK_Cfg Si3218x_FSK_Presets[] ={

+{

+{

+0x02232000L,	 /* FSK01 */

+0x077C2000L 	 /* FSK10 */

+},

+{

+0x0015C000L,	 /* FSKAMP0 (0.080 vrms )*/

+0x000BA000L 	 /* FSKAMP1 (0.080 vrms) */

+},

+{

+0x06B60000L,	 /* FSKFREQ0 (2200.0 Hz space) */

+0x079C0000L 	 /* FSKFREQ1 (1200.0 Hz mark) */

+},

+0x00,			 /* FSK8 */

+0x00,			 /* FSKDEPTH (1 deep fifo) */

+},  /* DEFAULT_FSK */

+{

+{

+0x026E4000L,	 /* FSK01 */

+0x0694C000L 	 /* FSK10 */

+},

+{

+0x0014C000L,	 /* FSKAMP0 (0.080 vrms )*/

+0x000CA000L 	 /* FSKAMP1 (0.080 vrms) */

+},

+{

+0x06D20000L,	 /* FSKFREQ0 (2100.0 Hz space) */

+0x078B0000L 	 /* FSKFREQ1 (1300.0 Hz mark) */

+},

+0x00,			 /* FSK8 */

+0x00,			 /* FSKDEPTH (1 deep fifo) */

+}   /* ETSI_FSK */

+};

+

+Si3218x_PulseMeter_Cfg Si3218x_PulseMeter_Presets[] ={

+{

+0x007A2B6AL,  /* PM_AMP_THRESH (1.000) */

+0,            /* Freq (12kHz) */ 

+0,            /* PM_AUTO (off)*/

+0x07D00000L,  /* PM_active (2000 ms) */

+0x07D00000L   /* PM_inactive (2000 ms) */

+ }   /* DEFAULT_PULSE_METERING */

+};

+

+Si3218x_Tone_Cfg Si3218x_Tone_Presets[] = {

+{

+	{

+	0x07B30000L,	 /* OSC1FREQ (350.000 Hz) */

+	0x000C6000L,	 /* OSC1AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x00,			 /* O1TALO (0 ms) */

+	0x00,			 /* O1TAHI */

+	0x00,			 /* O1TILO (0 ms) */

+	0x00			 /* O1TIHI */

+	},

+	{

+	0x07870000L,	 /* OSC2FREQ (440.000 Hz) */

+	0x000FA000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x00,			 /* O2TALO (0 ms) */

+	0x00,			 /* O2TAHI */

+	0x00,			 /* O2TILO (0 ms) */

+	0x00 			 /* O2TIHI */

+	},

+	0x66 			 /* OMODE */

+},  /* TONEGEN_FCC_DIAL */

+{

+	{

+	0x07700000L,	 /* OSC1FREQ (480.000 Hz) */

+	0x00112000L,	 /* OSC1AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0xA0,			 /* O1TALO (500 ms) */

+	0x0F,			 /* O1TAHI */

+	0xA0,			 /* O1TILO (500 ms) */

+	0x0F			 /* O1TIHI */

+	},

+	{

+	0x07120000L,	 /* OSC2FREQ (620.000 Hz) */

+	0x00164000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0xA0,			 /* O2TALO (500 ms) */

+	0x0F,			 /* O2TAHI */

+	0xA0,			 /* O2TILO (500 ms) */

+	0x0F 			 /* O2TIHI */

+	},

+	0x66 			 /* OMODE */

+},  /* TONEGEN_FCC_BUSY */

+{

+	{

+	0x07700000L,	 /* OSC1FREQ (480.000 Hz) */

+	0x00112000L,	 /* OSC1AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x80,			 /* O1TALO (2000 ms) */

+	0x3E,			 /* O1TAHI */

+	0x00,			 /* O1TILO (4000 ms) */

+	0x7D			 /* O1TIHI */

+	},

+	{

+	0x07870000L,	 /* OSC2FREQ (440.000 Hz) */

+	0x000FA000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x80,			 /* O2TALO (2000 ms) */

+	0x3E,			 /* O2TAHI */

+	0x00,			 /* O2TILO (4000 ms) */

+	0x7D 			 /* O2TIHI */

+	},

+	0x66 			 /* OMODE */

+},  /* TONEGEN_FCC_RINGBACK */

+{

+	{

+	0x07700000L,	 /* OSC1FREQ (480.000 Hz) */

+	0x00112000L,	 /* OSC1AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x60,			 /* O1TALO (300 ms) */

+	0x09,			 /* O1TAHI */

+	0x60,			 /* O1TILO (300 ms) */

+	0x09			 /* O1TIHI */

+	},

+	{

+	0x07120000L,	 /* OSC2FREQ (620.000 Hz) */

+	0x00164000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x60,			 /* O2TALO (300 ms) */

+	0x09,			 /* O2TAHI */

+	0x40,			 /* O2TILO (200 ms) */

+	0x06 			 /* O2TIHI */

+	},

+	0x66 			 /* OMODE */

+},  /* TONEGEN_FCC_REORDER */

+{

+	{

+	0x07700000L,	 /* OSC1FREQ (480.000 Hz) */

+	0x00112000L,	 /* OSC1AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x40,			 /* O1TALO (200 ms) */

+	0x06,			 /* O1TAHI */

+	0x40,			 /* O1TILO (200 ms) */

+	0x06			 /* O1TIHI */

+	},

+	{

+	0x07120000L,	 /* OSC2FREQ (620.000 Hz) */

+	0x00164000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x40,			 /* O2TALO (200 ms) */

+	0x06,			 /* O2TAHI */

+	0x40,			 /* O2TILO (200 ms) */

+	0x06 			 /* O2TIHI */

+	},

+	0x66 			 /* OMODE */

+},  /* TONEGEN_FCC_CONGESTION */

+{

+	{

+	0x1F2F0000L,	 /* OSC1FREQ (2130.000 Hz) */

+	0x0063A000L,	 /* OSC1AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x80,			 /* O1TALO (80 ms) */

+	0x02,			 /* O1TAHI */

+	0x80,			 /* O1TILO (80 ms) */

+	0x02			 /* O1TIHI */

+	},

+	{

+	0x1B8E0000L,	 /* OSC2FREQ (2750.000 Hz) */

+	0x00A84000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x80,			 /* O2TALO (80 ms) */

+	0x02,			 /* O2TAHI */

+	0x40,			 /* O2TILO (1000 ms) */

+	0x1F 			 /* O2TIHI */

+	},

+	0x66 			 /* OMODE */

+},  /* TONEGEN_FCC_CAS */

+{

+	{

+	0x07870000L,	 /* OSC1FREQ (440.000 Hz) */

+	0x000FA000L,	 /* OSC1AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x60,			 /* O1TALO (300 ms) */

+	0x09,			 /* O1TAHI */

+	0x00,			 /* O1TILO (8000 ms) */

+	0xFA			 /* O1TIHI */

+	},

+	{

+	0x1B8E0000L,	 /* OSC2FREQ (2750.000 Hz) */

+	0x00A84000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x80,			 /* O2TALO (2000 ms) */

+	0x3E,			 /* O2TAHI */

+	0x00,			 /* O2TILO (4000 ms) */

+	0x7D 			 /* O2TIHI */

+	},

+	0x06 			 /* OMODE */

+},  /* TONEGEN_FCC_SAS */

+{

+	{

+	0x1F2F0000L,	 /* OSC1FREQ (2130.000 Hz) */

+	0x01BD0000L,	 /* OSC1AMP (-5.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x20,			 /* O1TALO (100 ms) */

+	0x03,			 /* O1TAHI */

+	0x20,			 /* O1TILO (100 ms) */

+	0x03			 /* O1TIHI */

+	},

+	{

+	0x1B8E0000L,	 /* OSC2FREQ (2750.000 Hz) */

+	0x02EFC000L,	 /* OSC2AMP (-5.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x20,			 /* O2TALO (100 ms) */

+	0x03,			 /* O2TAHI */

+	0x20,			 /* O2TILO (100 ms) */

+	0x03 			 /* O2TIHI */

+	},

+	0x66 			 /* OMODE */

+},  /* TONEGEN_ETSI_DTAS */

+{

+	{

+	0x05A40000L,	 /* OSC1FREQ (1004.000 Hz) */

+	0x005DE000L,	 /* OSC1AMP (-10.000 dBm) */

+	0x00000000L,	 /* OSC1PHAS (0.000 rad) */

+	0x00,			 /* O1TALO (8000 ms) */

+	0xFA,			 /* O1TAHI */

+	0x00,			 /* O1TILO (8000 ms) */

+	0xFA			 /* O1TIHI */

+	},

+	{

+	0x07870000L,	 /* OSC2FREQ (440.000 Hz) */

+	0x000FA000L,	 /* OSC2AMP (-18.000 dBm) */

+	0x00000000L,	 /* OSC2PHAS (0.000 rad) */

+	0x80,			 /* O2TALO (2000 ms) */

+	0x3E,			 /* O2TAHI */

+	0x00,			 /* O2TILO (4000 ms) */

+	0x7D 			 /* O2TIHI */

+	},

+	0x47 			 /* OMODE */

+}   /* TONEGEN_1004 */

+};

+

+Si3218x_PCM_Cfg Si3218x_PCM_Presets[] ={

+	{

+	0x01, 	 /* PCM_FMT - u-Law */

+	0x00, 	 /* WIDEBAND - DISABLED (3.4kHz BW) */

+	0x00, 	 /* PCM_TRI - PCLK RISING EDGE */

+	0x00, 	 /* TX_EDGE - PCLK RISING EDGE */

+	0x00 	 /* A-LAW -  INVERT NONE */

+	},  /* PCM_8ULAW */

+	{

+	0x00, 	 /* PCM_FMT - A-Law */

+	0x00, 	 /* WIDEBAND - DISABLED (3.4kHz BW) */

+	0x00, 	 /* PCM_TRI - PCLK RISING EDGE */

+	0x00, 	 /* TX_EDGE - PCLK RISING EDGE */

+	0x00 	 /* A-LAW -  INVERT NONE */

+	},  /* PCM_8ALAW */

+	{

+	0x03, 	 /* PCM_FMT - 16-bit Linear */

+	0x00, 	 /* WIDEBAND - DISABLED (3.4kHz BW) */

+	0x00, 	 /* PCM_TRI - PCLK RISING EDGE */

+	0x00, 	 /* TX_EDGE - PCLK RISING EDGE */

+	0x00 	 /* A-LAW -  INVERT NONE */

+	},  /* PCM_16LIN */

+	{

+	0x03, 	 /* PCM_FMT - 16-bit Linear */

+	0x01, 	 /* WIDEBAND - ENABLED (7kHz BW) */

+	0x00, 	 /* PCM_TRI - PCLK RISING EDGE */

+	0x00, 	 /* TX_EDGE - PCLK RISING EDGE */

+	0x00 	 /* A-LAW -  INVERT NONE */

+	}   /* PCM_16LIN_WB */

+};

+

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

+

diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si_voice.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si_voice.c
new file mode 100644
index 0000000..c30ee2c
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si_voice.c
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 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 file contains common (ProSIC + DAA) functions.
+ *
+ */
+
+#include "../config_inc/si_voice_datatypes.h"
+#include "../inc/si_voice.h"
+#include "../config_inc/proslic_api_config.h"
+
+#ifdef ENABLE_DEBUG
+#define LOGPRINT_PREFIX "SiVoice: "
+#endif
+
+#ifdef SI3217X
+#include "si3217x.h"
+#include "si3217x_intf.h"
+#endif
+
+#ifdef SI3218X
+#include "../inc/si3218x.h"
+#include "../inc/si3218x_intf.h"
+#endif
+
+#ifdef SI3219X
+#include "si3219x.h"
+#include "si3219x_intf.h"
+#endif
+
+#ifdef SI3226X
+#include "si3226x.h"
+#include "si3226x_intf.h"
+#endif
+
+#ifdef SI3228X
+#include "si3228x.h"
+#include "si3228x_intf.h"
+#endif
+
+#define pCtrl(X)           (X)->deviceId->ctrlInterface
+#define pProHW(X)          pCtrl((X))->hCtrl
+#define ReadReg(PCHAN, CHANNEL, REGADDR) (PCHAN)->deviceId->ctrlInterface->ReadRegister_fptr(pProHW(PCHAN), (CHANNEL), (REGADDR))
+#define WriteReg(PCHAN, CHANNEL, REGADDR, REGDATA) (PCHAN)->deviceId->ctrlInterface->WriteRegister_fptr(pProHW(PCHAN), (CHANNEL), (REGADDR), (REGDATA))
+
+/*
+** Control object constructor/destructor
+*/
+int SiVoice_createControlInterfaces (SiVoiceControlInterfaceType **pCtrlIntf,
+                                     uInt32 interface_count)
+{
+  TRACEPRINT_NOCHAN("count = %lu\n", (unsigned long)interface_count);
+#ifndef DISABLE_MALLOC
+  *pCtrlIntf = SIVOICE_CALLOC(sizeof(SiVoiceControlInterfaceType),
+                              interface_count);
+  if(*pCtrlIntf == NULL)
+  {
+#ifdef ENABLE_DEBUG
+    LOGPRINT("%s%s: failed to allocate memory", LOGPRINT_PREFIX, __FUNCTION__);
+#endif
+    return RC_NO_MEM;
+  }
+
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pCtrlIntf);
+  SILABS_UNREFERENCED_PARAMETER(interface_count);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+int SiVoice_destroyControlInterfaces ( SiVoiceControlInterfaceType **pCtrlIntf )
+{
+
+  TRACEPRINT_NOCHAN("\n",NULL);
+#ifndef DISABLE_MALLOC
+  if( pCtrlIntf && *pCtrlIntf)
+  {
+    SIVOICE_FREE ((SiVoiceControlInterfaceType *)*pCtrlIntf);
+    *pCtrlIntf = NULL;
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pCtrlIntf);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+/*
+** Device object constructor/destructor
+*/
+int SiVoice_createDevices (SiVoiceDeviceType **pDevice, uInt32 device_count)
+{
+
+  TRACEPRINT_NOCHAN("\n",NULL);
+#ifndef DISABLE_MALLOC
+  *pDevice = SIVOICE_CALLOC (sizeof(SiVoiceDeviceType), device_count);
+
+  if(*pDevice == NULL)
+  {
+#ifdef ENABLE_DEBUG
+    LOGPRINT("%s%s: failed to allocate memory", LOGPRINT_PREFIX, __FUNCTION__);
+#endif
+    return RC_NO_MEM;
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pDevice);
+  SILABS_UNREFERENCED_PARAMETER(device_count);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+int SiVoice_destroyDevices (SiVoiceDeviceType **pDevice)
+{
+
+  TRACEPRINT_NOCHAN("\n", NULL);
+#ifndef DISABLE_MALLOC
+  if(pDevice && *pDevice)
+  {
+    SIVOICE_FREE ((SiVoiceDeviceType *)*pDevice);
+    *pDevice = NULL;
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pDevice);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+/*
+** Channel object constructor/destructor
+*/
+int SiVoice_createChannels (SiVoiceChanType_ptr *pChan, uInt32 channel_count)
+{
+
+  TRACEPRINT_NOCHAN("count = %lu\n", (unsigned long) channel_count);
+#ifndef DISABLE_MALLOC
+  *pChan = SIVOICE_CALLOC(sizeof(SiVoiceChanType),channel_count);
+  if(*pChan == NULL)
+  {
+#ifdef ENABLE_DEBUG
+    LOGPRINT("%s%s: failed to allocate memory", LOGPRINT_PREFIX, __FUNCTION__);
+#endif
+    return RC_NO_MEM;
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(pChan);
+  SILABS_UNREFERENCED_PARAMETER(channel_count);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+int SiVoice_destroyChannels (SiVoiceChanType_ptr *hProslic)
+{
+
+  TRACEPRINT_NOCHAN("\n",NULL);
+#ifndef DISABLE_MALLOC
+  if(hProslic && *hProslic)
+  {
+    SIVOICE_FREE ((SiVoiceChanType_ptr)*hProslic);
+    *hProslic = NULL;
+  }
+  return RC_NONE;
+#else
+  SILABS_UNREFERENCED_PARAMETER(hProslic);
+  return RC_UNSUPPORTED_FEATURE;
+#endif
+}
+
+/*
+** Host control linkage
+*/
+int SiVoice_setControlInterfaceCtrlObj (SiVoiceControlInterfaceType *pCtrlIntf,
+                                        void *hCtrl)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->hCtrl = hCtrl;
+  return RC_NONE;
+}
+
+/*
+** Host reset linkage
+*/
+int SiVoice_setControlInterfaceReset (SiVoiceControlInterfaceType *pCtrlIntf,
+                                      ctrl_Reset_fptr Reset_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->Reset_fptr = Reset_fptr;
+  return RC_NONE;
+}
+
+/*
+** Host register/RAM read/write linkage
+*/
+int SiVoice_setControlInterfaceWriteRegister (SiVoiceControlInterfaceType
+    *pCtrlIntf, ctrl_WriteRegister_fptr WriteRegister_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->WriteRegister_fptr = WriteRegister_fptr;
+  return RC_NONE;
+}
+
+int SiVoice_setControlInterfaceReadRegister (SiVoiceControlInterfaceType
+    *pCtrlIntf, ctrl_ReadRegister_fptr ReadRegister_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->ReadRegister_fptr = ReadRegister_fptr;
+  return RC_NONE;
+}
+
+int SiVoice_setControlInterfaceWriteRAM (SiVoiceControlInterfaceType *pCtrlIntf,
+    ctrl_WriteRAM_fptr WriteRAM_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->WriteRAM_fptr = WriteRAM_fptr;
+  return RC_NONE;
+}
+
+int SiVoice_setControlInterfaceReadRAM (SiVoiceControlInterfaceType *pCtrlIntf,
+                                        ctrl_ReadRAM_fptr ReadRAM_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->ReadRAM_fptr = ReadRAM_fptr;
+  return RC_NONE;
+}
+
+/*
+** Host timer linkage
+*/
+int SiVoice_setControlInterfaceTimerObj (SiVoiceControlInterfaceType *pCtrlIntf,
+    void *hTimer)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->hTimer = hTimer;
+  return RC_NONE;
+}
+
+int SiVoice_setControlInterfaceDelay (SiVoiceControlInterfaceType *pCtrlIntf,
+                                      system_delay_fptr Delay_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->Delay_fptr = Delay_fptr;
+  return RC_NONE;
+}
+
+int SiVoice_setControlInterfaceSemaphore (SiVoiceControlInterfaceType
+    *pCtrlIntf, ctrl_Semaphore_fptr semaphore_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->Semaphore_fptr = semaphore_fptr;
+  return RC_NONE;
+}
+
+int SiVoice_setControlInterfaceTimeElapsed (SiVoiceControlInterfaceType
+    *pCtrlIntf, system_timeElapsed_fptr timeElapsed_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->timeElapsed_fptr = timeElapsed_fptr;
+  return RC_NONE;
+}
+
+int SiVoice_setControlInterfaceGetTime (SiVoiceControlInterfaceType *pCtrlIntf,
+                                        system_getTime_fptr getTime_fptr)
+{
+  TRACEPRINT_NOCHAN("\n",NULL);
+  pCtrlIntf->getTime_fptr = getTime_fptr;
+  return RC_NONE;
+}
+
+/*
+** Channel object initialization
+*/
+int SiVoice_SWInitChan (SiVoiceChanType_ptr pChan,int channel,int chipType,
+                        SiVoiceDeviceType *pDeviceObj, SiVoiceControlInterfaceType *pCtrlIntf)
+{
+  TRACEPRINT_NOCHAN( "channel = %d chipType = %d\n", channel, chipType);
+  pChan->channel = (uInt8)channel;
+  pChan->deviceId = pDeviceObj;
+  pChan->deviceId->ctrlInterface = pCtrlIntf;
+  pChan->channelEnable=1;
+  pChan->error = RC_NONE;
+  pChan->debugMode = 0;
+  pChan->dcdc_polarity_invert = 0;
+#ifdef PROSLIC_BOM_DEFAULT
+  pChan->bomOption = PROSLIC_BOM_DEFAULT;
+#else
+  pChan->bomOption = 0;
+#endif
+
+  switch (chipType)
+  {
+    case SI3217X_TYPE:
+      pChan->deviceId->chipType = SI32171;
+      break;
+
+    case SI3218X_TYPE:
+      pChan->deviceId->chipType = SI32180;
+      break;
+
+    case SI3219X_TYPE:
+      pChan->deviceId->chipType = SI32190;
+      break;
+
+    case SI3226X_TYPE:
+      pChan->deviceId->chipType = SI32260;
+      break;
+
+    case SI3228X_TYPE:
+      pChan->deviceId->chipType = SI32280;
+      break;
+
+    case SI3050_TYPE:
+      pChan->deviceId->chipType = SI3050;
+      break;
+
+    default:
+      return RC_UNSUPPORTED_FEATURE;
+  }
+  return RC_NONE;
+}
+
+/*
+** Reset control
+*/
+int SiVoice_Reset (SiVoiceChanType_ptr pChan)
+{
+  TRACEPRINT_NOCHAN( "\n", NULL);
+  /*
+  ** assert reset, wait 250ms, release reset, wait 250ms
+  */
+  pChan->deviceId->ctrlInterface->Reset_fptr(
+    pChan->deviceId->ctrlInterface->hCtrl,1);
+
+  pChan->deviceId->ctrlInterface->Delay_fptr(
+    pChan->deviceId->ctrlInterface->hTimer,250);
+
+  pChan->deviceId->ctrlInterface->Reset_fptr(
+    pChan->deviceId->ctrlInterface->hCtrl,0);
+
+  pChan->deviceId->ctrlInterface->Delay_fptr(
+    pChan->deviceId->ctrlInterface->hTimer,250);
+
+  return RC_NONE;
+}
+
+/*
+** Debug Mode Control
+*/
+int SiVoice_setSWDebugMode (SiVoiceChanType_ptr pChan, int debugEn)
+{
+#ifdef ENABLE_DEBUG
+  TRACEPRINT_NOCHAN( "debugEn %d\n", debugEn);
+  pChan->debugMode = (0xFE & pChan->debugMode) | (debugEn != 0);
+#else
+  SILABS_UNREFERENCED_PARAMETER(pChan);
+  SILABS_UNREFERENCED_PARAMETER(debugEn);
+#endif
+  return RC_NONE;
+}
+
+/*
+** Trace Mode Control
+*/
+int SiVoice_setTraceMode (SiVoiceChanType_ptr pChan, int traceEn)
+{
+#ifdef ENABLE_TRACES
+  TRACEPRINT_NOCHAN( "debugEn %d\n", traceEn);
+  pChan->debugMode = (0xFD & pChan->debugMode) | ((traceEn != 0)<<1);
+#else
+  SILABS_UNREFERENCED_PARAMETER(pChan);
+  SILABS_UNREFERENCED_PARAMETER(traceEn);
+#endif
+  return RC_NONE;
+}
+
+/*
+** Error status
+*/
+int SiVoice_getErrorFlag (SiVoiceChanType_ptr pChan, int *error)
+{
+  TRACEPRINT( pChan, "\n", NULL);
+  *error = pChan->error;
+  return RC_NONE;
+}
+
+int SiVoice_clearErrorFlag (SiVoiceChanType_ptr pChan)
+{
+  TRACEPRINT( pChan, "\n", NULL);
+  pChan->error = RC_NONE;
+  return RC_NONE;
+}
+
+/*
+** Channel status
+*/
+int SiVoice_setChannelEnable (SiVoiceChanType_ptr pChan, int chanEn)
+{
+  TRACEPRINT( pChan, "enable = %d\n", chanEn);
+  pChan->channelEnable = chanEn;
+  return RC_NONE;
+}
+
+int SiVoice_getChannelEnable (SiVoiceChanType_ptr pChan, int *chanEn)
+{
+  TRACEPRINT( pChan, "\n", NULL);
+  *chanEn = pChan->channelEnable;
+  return RC_NONE;
+}
+
+uInt8 SiVoice_ReadReg(SiVoiceChanType_ptr hProslic,uInt8 addr)
+{
+  TRACEPRINT( hProslic, "addr = %u\n", (unsigned int)addr);
+  return ReadReg(hProslic, hProslic->channel, addr);
+}
+
+int SiVoice_WriteReg(SiVoiceChanType_ptr hProslic,uInt8 addr,uInt8 data)
+{
+  TRACEPRINT( hProslic, "addr = %u data = 0x%02X\n", (unsigned int)addr,
+              (unsigned int) data);
+  return WriteReg(hProslic, hProslic->channel, addr, data);
+}
+
+/*****************************************************************************************************/
+#if defined(SI3217X) || defined(SI3218X) || defined(SI3219X) || defined(SI3226X) || defined(SI3228X) 
+#include "../inc/proslic.h"
+
+/* Iterate through the number of channels to determine if it's a SLIC, DAA, or unknown. Rev ID and chiptype is
+ * also filled in.
+ */
+int SiVoice_IdentifyChannels(SiVoiceChanType_ptr *pProslic, int size,
+                             int *slicCount, int *daaCount)
+{
+  int i;
+  int rc = RC_NONE;
+  SiVoiceChanType_ptr currentChannel;
+
+  TRACEPRINT( *pProslic, "size = %d\n", size);
+
+  if(slicCount)
+  {
+    *slicCount = 0;
+  }
+  if(daaCount)
+  {
+    *daaCount = 0;
+  }
+
+  for(i = 0; i < size; i++)
+  {
+    currentChannel = pProslic[i];
+    /* SiVoice_SWInitChan() fills in the chipType initially with something the user provided, fill it
+     * in with the correct info.. The GetChipInfo may probe registers to compare them with their
+     * initial values, so this function MUST only be called after a chipset reset.
+     */
+#ifdef SI3217X
+    if (currentChannel->deviceId->chipType >= SI32171
+        && currentChannel->deviceId->chipType <= SI32179)
+    {
+      rc = Si3217x_GetChipInfo(currentChannel);
+    }
+#endif
+
+#ifdef SI3218X
+    if (currentChannel->deviceId->chipType >= SI32180
+        && currentChannel->deviceId->chipType <= SI32189)
+    {
+      rc = Si3218x_GetChipInfo(currentChannel);
+    }
+#endif
+
+#ifdef SI3219X
+    if ( IS_SI3219X(currentChannel->deviceId) )
+    {
+      rc = Si3219x_GetChipInfo(currentChannel);
+    }
+#endif
+
+#ifdef SI3226X
+    if (currentChannel->deviceId->chipType >= SI32260
+        && currentChannel->deviceId->chipType <= SI32269)
+    {
+      rc = Si3226x_GetChipInfo(currentChannel);
+    }
+#endif
+
+#ifdef SI3228X
+    if (currentChannel->deviceId->chipType >= SI32280
+        && currentChannel->deviceId->chipType <= SI32289)
+    {
+      rc = Si3228x_GetChipInfo(currentChannel);
+    }
+#endif
+
+    if(rc != RC_NONE)
+    {
+      return rc;
+    }
+
+    currentChannel->channelType = ProSLIC_identifyChannelType(currentChannel);
+    if(currentChannel->channelType == PROSLIC)
+    {
+      if(slicCount)
+      {
+        (*slicCount)++;
+      }
+    }
+    else if(currentChannel->channelType == DAA)
+    {
+      if(daaCount)
+      {
+        (*daaCount)++;
+      }
+    }
+#ifdef ENABLE_DEBUG
+    {
+      const char *dev_type = "UNKNOWN";
+      if(currentChannel->channelType == PROSLIC)
+      {
+        dev_type = "PROSLIC";
+      }
+      else if(currentChannel->channelType == DAA)
+      {
+        dev_type = "DAA";
+      }
+      LOGPRINT("%sChannel %d: Type = %s Rev = %d\n",
+               LOGPRINT_PREFIX, currentChannel->channel, dev_type,
+               currentChannel->deviceId->chipRev);
+
+    }
+#endif /* ENABLE_DEBUG */
+  }
+  return RC_NONE;
+}
+#endif
+
+/*
+** Function: ProSLIC_Version
+**
+** Description:
+** Return API version
+**
+** Returns:
+** string of the API release.
+*/
+
+extern const char *SiVoiceAPIVersion;
+char *SiVoice_Version()
+{
+  return (char *)SiVoiceAPIVersion;
+}
+
diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si_voice_version.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si_voice_version.c
new file mode 100644
index 0000000..5d4aaaa
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/si_voice_version.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * file: si_voice_version.c
+ *
+ * Distributed by: 
+ * Silicon Laboratories, Inc
+ *
+ * This file contains proprietary information.	 
+ * No dissemination allowed without prior written permission from
+ * Silicon Laboratories, Inc.
+ * 
+ * THIS FILE IS AUTOGENERATED - DO NOT MODIFY
+ *
+ */
+
+
+
+char *SiVoiceAPIVersion = "9.2.0";
+
+
+
diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/vdaa.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/vdaa.c
new file mode 100644
index 0000000..9a73c44
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/vdaa.c
@@ -0,0 +1,1350 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Vdaa  VoiceDAA interface implementation file
+ *
+ * Distributed by:
+ * Silicon Laboratories, Inc
+ *
+ * This file contains proprietary information.
+ * No dissemination allowed without prior written permission from
+ * Silicon Laboratories, Inc.
+ *
+ * File Description:
+ * This is the implementation file for the main VoiceDAA API.
+ *
+ */
+
+#include "../config_inc/si_voice_datatypes.h"
+#include "../inc/si_voice_ctrl.h"
+#include "../inc/si_voice_timer_intf.h"
+#include "../inc/vdaa.h"
+#include "../inc/vdaa_registers.h"
+#include "../config_inc/vdaa_api_config.h"
+
+#define WriteReg      pVdaa->deviceId->ctrlInterface->WriteRegister_fptr
+#define ReadReg        pVdaa->deviceId->ctrlInterface->ReadRegister_fptr
+#define pVdaaHW        pVdaa->deviceId->ctrlInterface->hCtrl
+
+#define WriteRegX      deviceId->ctrlInterface->WriteRegister_fptr
+#define ReadRegX      deviceId->ctrlInterface->ReadRegister_fptr
+#define pVdaaHWX      deviceId->ctrlInterface->hCtrl
+#define LOGPRINT_PREFIX "VDAA: "
+
+/*
+** Static VDAA driver functions
+*/
+
+/*
+** Function: isVerifiedDAA
+**
+** Description:
+** Verifies addressed channel is DAA
+**
+** Input Parameters:
+** pVdaa: pointer to SiVoiceChanType or vdaaChanType
+**
+** Return:
+** Verified DAA
+** Not DAA          RC_CHANNEL_TYPE_ERR
+**
+*/
+
+static int isVerifiedDAA(vdaaChanType *pVdaa)
+{
+  uInt8 data = ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV);
+  if ( (data & 0x40) == 0 ) /*This bit is always 1 for DAA*/
+  {
+    LOGPRINT("%sDAA device not detected\n",LOGPRINT_PREFIX);
+    return RC_CHANNEL_TYPE_ERR;
+  }
+  else
+  {
+    /* For Si3050, the value will be zero initially (calloc), for Si32178/9, this will
+     * be non-zero (Rev B).
+     */
+    if(pVdaa->deviceId->chipRev == 0)
+    {
+      /* Read Device ID and store it */
+      /* NOTE: in earlier releases we also read the line side info here.  This is now done
+         Vdaa_duringPowerUpLineside since the information we read was always 0.
+       */
+      data = pVdaa->ReadRegX(pVdaa->pVdaaHWX,pVdaa->channel,SYS_LINE_DEV_REV);
+      pVdaa->deviceId->chipRev= data&0xF;
+#ifdef ENABLE_DEBUG
+      LOGPRINT("%sChipRev = 0x%x\n", LOGPRINT_PREFIX, pVdaa->deviceId->chipRev);
+#endif
+    }
+  }
+
+  return RC_NONE;
+}
+
+#if 0 /* Removed for now since it isn't used, keeping code as reference */
+/*
+** Function: probeDaisyChain
+**
+** Description:
+** Identify how many VDAA devices are in daisychain
+** Only called if channel 0 has be previously qualified
+** as a VDAA.
+**
+** Input Parameters:
+** pVdaa:       pointer to SiVoiceChanType or vdaaChanType
+**
+** Return:
+** number of channels in daisy chain
+**
+*/
+
+static int probeDaisyChain (vdaaChanType *pVdaa)
+{
+  int i=0;
+  WriteReg(pVdaaHW,BROADCAST,PCMRX_CNT_LO,0x23);        /* Broadcast */
+  while ((ReadReg(pVdaaHW,(uInt8)i++,PCMRX_CNT_LO) == 0x23)
+         &&(i<=16));  /* Count number of channels */
+  return i-1;                          /* Return number of channels */
+}
+#endif
+
+/*
+**
+**  ------ VDAA CONFIGURATION FUNCTIONS -----
+**
+*/
+
+/*
+** Function:  Vdaa_RingDetectSetup
+**
+** Description:
+** configure ring detect setup
+**
+** Returns:
+**
+*/
+
+#ifndef DISABLE_VDAA_RING_DETECT_SETUP
+extern vdaa_Ring_Detect_Cfg Vdaa_Ring_Detect_Presets[];
+int Vdaa_RingDetectSetup (vdaaChanType *pVdaa,int32 preset)
+{
+
+  uInt8 regTemp = 0;
+  TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2) & 0xfB;
+  regTemp |= Vdaa_Ring_Detect_Presets[preset].rdi<<2;
+  WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp);
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL1) & 0xfe;
+  regTemp |= Vdaa_Ring_Detect_Presets[preset].rt&1;
+  WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL1,regTemp);
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL2) & 0xef;
+  regTemp |= ((Vdaa_Ring_Detect_Presets[preset].rt>>1)<<4);
+  WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
+
+  WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL3,
+           Vdaa_Ring_Detect_Presets[preset].rfwe<<1);
+
+  regTemp = (Vdaa_Ring_Detect_Presets[preset].rdly&0x3) << 6;
+  regTemp |= Vdaa_Ring_Detect_Presets[preset].rmx ;
+  WriteReg(pVdaaHW,pVdaa->channel,RNG_VLD_CTRL1,regTemp);
+
+  regTemp = (Vdaa_Ring_Detect_Presets[preset].rdly>>2) << 7;
+  regTemp |= Vdaa_Ring_Detect_Presets[preset].rto << 3 ;
+  regTemp |= Vdaa_Ring_Detect_Presets[preset].rcc ;
+  WriteReg(pVdaaHW,pVdaa->channel,RNG_VLD_CTRL2,regTemp);
+
+  regTemp = Vdaa_Ring_Detect_Presets[preset].rngv << 7;
+  regTemp |= Vdaa_Ring_Detect_Presets[preset].ras ;
+  WriteReg(pVdaaHW,pVdaa->channel,RNG_VLD_CTRL3,regTemp);
+
+  regTemp = Vdaa_Ring_Detect_Presets[preset].rpol<<1;
+  WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL4,regTemp);
+
+  return RC_NONE;
+}
+#endif
+
+/*
+** Function:  Vdaa_TXAudioGainSetup
+**
+** Description:
+** configure tx audio gain
+**
+** Returns:
+**
+**
+*/
+#ifndef DISABLE_VDAA_AUDIO_GAIN_SETUP
+extern vdaa_audioGain_Cfg Vdaa_audioGain_Presets[];
+
+int Vdaa_TXAudioGainSetup (vdaaChanType *pVdaa,int32 preset)
+{
+  uInt8 regTemp = 0;
+  TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
+
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  if(Vdaa_audioGain_Presets[preset].xga2 == XGA_ATTEN)
+  {
+    regTemp = 0x10;
+  }
+
+  regTemp |= Vdaa_audioGain_Presets[preset].acgain2 ;
+  WriteReg(pVdaaHW,pVdaa->channel,TX_GN_CTRL2,regTemp);
+
+  regTemp = 0;
+  if(Vdaa_audioGain_Presets[preset].xga3 == XGA_ATTEN)
+  {
+    regTemp = 0x10 ;
+  }
+
+  regTemp |= Vdaa_audioGain_Presets[preset].acgain3 ;
+  WriteReg(pVdaaHW,pVdaa->channel,TX_GN_CTRL3,regTemp);
+
+  if(Vdaa_audioGain_Presets[preset].cpEn)
+  {
+    WriteReg(pVdaaHW,pVdaa->channel,TXCALL_PROG_ATTEN,
+             Vdaa_audioGain_Presets[preset].callProgress);
+  }
+
+  return RC_NONE;
+}
+# endif
+
+
+/*
+** Function:  Vdaa_RXAudioGainSetup
+**
+** Description:
+** configure rx audio gain
+**
+** Returns:
+**
+**
+*/
+#ifndef DISABLE_VDAA_AUDIO_GAIN_SETUP
+extern vdaa_audioGain_Cfg Vdaa_audioGain_Presets[];
+
+int Vdaa_RXAudioGainSetup (vdaaChanType *pVdaa,int32 preset)
+{
+  uInt8 regTemp = 0;
+
+  TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  if(Vdaa_audioGain_Presets[preset].xga2 == XGA_ATTEN)
+  {
+    regTemp = 0x10;
+  }
+  regTemp |= Vdaa_audioGain_Presets[preset].acgain2 ;
+  WriteReg(pVdaaHW,pVdaa->channel,RX_GN_CTRL2,regTemp);
+
+  regTemp = 0;
+  if(Vdaa_audioGain_Presets[preset].xga3 == XGA_ATTEN)
+  {
+    regTemp = 0x10;
+  }
+  regTemp |= Vdaa_audioGain_Presets[preset].acgain3 ;
+  WriteReg(pVdaaHW,pVdaa->channel,RX_GN_CTRL3,regTemp);
+
+  if(Vdaa_audioGain_Presets[preset].cpEn)
+  {
+    WriteReg(pVdaaHW,pVdaa->channel,RXCALL_PROG_ATTEN,
+             Vdaa_audioGain_Presets[preset].callProgress);
+  }
+
+  return RC_NONE;
+}
+#endif
+
+
+/*
+** Function:  Vdaa_PCMSetup
+**
+** Description:
+** configure pcm format, clocking and edge placement
+**
+** Returns:
+**
+**
+*/
+#ifndef DISABLE_VDAA_PCM_SETUP
+extern vdaa_PCM_Cfg Vdaa_PCM_Presets [];
+
+int Vdaa_PCMSetup (vdaaChanType *pVdaa,int32 preset)
+{
+  uInt8 regTemp = 0;
+
+  TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL)&0xe0;
+  regTemp |= Vdaa_PCM_Presets[preset].pcm_tri;
+  regTemp |= Vdaa_PCM_Presets[preset].pcmHwy << 1;
+  regTemp |= Vdaa_PCM_Presets[preset].pcmFormat << 3;
+  WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,regTemp);
+
+  return RC_NONE;
+}
+#endif
+
+/*
+** Function:  Vdaa_PCMTimeSlotSetup
+**
+** Description:
+** configure pcm timeslot
+**
+** Returns:
+**
+*/
+int Vdaa_PCMTimeSlotSetup (vdaaChanType *pVdaa, uInt16 rxcount, uInt16 txcount)
+{
+  uInt8 data = 0;
+  uInt8 pcmStatus;
+
+  TRACEPRINT( pVdaa, "rxcount = %u txcount = %u\n", (unsigned int)rxcount,
+              (unsigned int)txcount);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  /* Disable PCM if enabled - restore after updating timeslots */
+  pcmStatus = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
+  if (pcmStatus&0x20)
+  {
+    WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,pcmStatus&~(0x20));
+  }
+
+  /*Storing 10 bit value of Transmit PCM sample in REG 34 and REG 35[0:1]*/
+  data = (uInt8)(txcount & 0xff);
+  WriteReg(pVdaaHW,pVdaa->channel,PCMTX_CNT_LO,data);
+  data = (uInt8)(txcount >> 8) ;
+  WriteReg(pVdaaHW,pVdaa->channel,PCMTX_CNT_HI,data);
+
+  /*Storing 10 bit value of Receive PCM sample in REG 34 and REG 35[0:1]*/
+  data = (uInt8)(rxcount & 0xff);
+  WriteReg(pVdaaHW,pVdaa->channel,PCMRX_CNT_LO,data);
+  data = (uInt8)(rxcount >> 8);
+  WriteReg(pVdaaHW,pVdaa->channel,PCMRX_CNT_HI,data);
+
+  /* Enable back the PCM after storing the values*/
+  WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,pcmStatus);
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_CountrySetup
+**
+** Description:
+** configure country specific settings
+**
+** Returns:
+**
+**
+*/
+
+#ifndef DISABLE_VDAA_COUNTRY_SETUP
+extern vdaa_Country_Cfg Vdaa_Country_Presets [];
+
+int Vdaa_CountrySetup (vdaaChanType *pVdaa,int32 preset)
+{
+  uInt8 regTemp = 0;
+
+  TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2) & 0xFD;
+  WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp); /* disable hybrid */
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL1) & 0xFD;
+  regTemp |= Vdaa_Country_Presets[preset].rz << 1 ;
+  WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL1,regTemp);
+
+  regTemp = Vdaa_Country_Presets[preset].dcr;
+  regTemp |= Vdaa_Country_Presets[preset].ilim<<1;
+  regTemp |= Vdaa_Country_Presets[preset].mini<<4;
+  regTemp |= Vdaa_Country_Presets[preset].dcv<<6;
+  WriteReg(pVdaaHW,pVdaa->channel,DC_TERM_CTRL,regTemp);
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,AC_TERM_CTRL) & 0xF0;
+  regTemp |= Vdaa_Country_Presets[preset].acim;
+  WriteReg(pVdaaHW,pVdaa->channel,AC_TERM_CTRL,regTemp);
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,SPRK_QNCH_CTRL) & 0xAF;
+  regTemp |= ((Vdaa_Country_Presets[preset].ohs_sq >> 2)&1)<<4 ;
+  regTemp |= ((Vdaa_Country_Presets[preset].ohs_sq >> 3)&1)<<6 ;
+  WriteReg(pVdaaHW,pVdaa->channel,SPRK_QNCH_CTRL,regTemp);
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL1) & 0xBF;
+  regTemp |= ((Vdaa_Country_Presets[preset].ohs_sq >> 1)&1)<<6 ;
+  WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL1,regTemp);
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL5) & 0xE7;
+  regTemp |= (Vdaa_Country_Presets[preset].ohs_sq&1)<<3 ;
+  WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL5,regTemp);
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2) & 0xFD;
+  regTemp |= (Vdaa_Country_Presets[preset].hbe)<<1 ;
+  WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp);
+
+  return RC_NONE;
+}
+#endif
+
+/*
+** Function:  Vdaa_HybridSetup
+**
+** Description:
+** configure hybrid
+**
+*/
+
+#ifndef DISABLE_VDAA_HYBRID_SETUP
+extern vdaa_Hybrid_Cfg Vdaa_Hybrid_Presets [];
+
+int Vdaa_HybridSetup (vdaaChanType *pVdaa,int32 preset)
+{
+  uInt8 regSave = 0;
+
+  TRACEPRINT( pVdaa, "preset = %d\n", (unsigned int) preset);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  regSave = ReadReg(pVdaaHW,pVdaa->channel,CTRL2);
+  WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regSave&0xFD); /* disable hybrid */
+
+  WriteReg(pVdaaHW,pVdaa->channel,HYB1,Vdaa_Hybrid_Presets[preset].hyb1);
+  WriteReg(pVdaaHW,pVdaa->channel,HYB2,Vdaa_Hybrid_Presets[preset].hyb2);
+  WriteReg(pVdaaHW,pVdaa->channel,HYB3,Vdaa_Hybrid_Presets[preset].hyb3);
+  WriteReg(pVdaaHW,pVdaa->channel,HYB4,Vdaa_Hybrid_Presets[preset].hyb4);
+  WriteReg(pVdaaHW,pVdaa->channel,HYB5,Vdaa_Hybrid_Presets[preset].hyb5);
+  WriteReg(pVdaaHW,pVdaa->channel,HYB6,Vdaa_Hybrid_Presets[preset].hyb6);
+  WriteReg(pVdaaHW,pVdaa->channel,HYB7,Vdaa_Hybrid_Presets[preset].hyb7);
+  WriteReg(pVdaaHW,pVdaa->channel,HYB8,Vdaa_Hybrid_Presets[preset].hyb8);
+
+  WriteReg(pVdaaHW,pVdaa->channel,CTRL2,
+           regSave); /* Restore hybrid enable state at entry */
+
+  return RC_NONE;
+}
+#endif
+
+/*
+** Function:  Vdaa_SetAudioMute
+**
+** Description:
+** Control RX and TX mute
+**
+*/
+
+int Vdaa_SetAudioMute(vdaaChanType *pVdaa, tMUTE mute)
+{
+  uInt8 regData;
+
+  TRACEPRINT( pVdaa, "mode = %u\n", (unsigned int) mute);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  regData = ReadReg(pVdaaHW,pVdaa->channel,TXRX_GN_CTRL);
+
+  switch(mute)
+  {
+    case MUTE_DISABLE_ALL:
+      regData = 0;
+      break;
+
+    case MUTE_DISABLE_RX:
+      regData &= 0x80;
+      break;
+
+    case MUTE_DISABLE_TX:
+      regData &= 0x08;
+      break;
+
+    case MUTE_ENABLE_RX:
+      regData |= 0x08;
+      break;
+
+    case MUTE_ENABLE_TX:
+      regData |= 0x80;
+      break;
+
+    case MUTE_ENABLE_ALL:
+      regData = 0x88;
+      break;
+  }
+
+  WriteReg(pVdaaHW,pVdaa->channel,TXRX_GN_CTRL,regData);
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_PCMStart
+**
+** Description:
+** Enables PCM bus
+**
+*/
+
+int Vdaa_PCMStart (vdaaChanType *pVdaa)
+{
+  uInt8 data = 0;
+
+  TRACEPRINT( pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  /*Enable PCM transfers by setting REG 33[5]=1 */
+  data = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
+  data |= 0x20;
+  WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,data);
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_PCMStop
+**
+** Description:
+** Disables PCM bus
+**
+*/
+
+int Vdaa_PCMStop (vdaaChanType *pVdaa)
+{
+  uInt8 data = 0;
+
+  TRACEPRINT( pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  /*disable PCM transfers by setting REG 33[5]=0 */
+  data = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
+  data &= ~(0x20);
+  WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL,data);
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_SetInterruptMask
+**
+** Description:
+** Enables interrupts based on passed 9-bit bitmask.  Bit
+** values defined by vdaaIntMask enum.
+**
+*/
+
+int Vdaa_SetInterruptMask(vdaaChanType *pVdaa, vdaaIntMask bitmask)
+{
+  uInt8 intMaskReg = 0;
+  uInt8 cviReg = 0;
+
+  TRACEPRINT( pVdaa, "mask = 0x%03x\n", (unsigned int)bitmask);
+  /* Channel validation */
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_CHANNEL_TYPE_ERR;
+  }
+
+  intMaskReg = (uInt8)(bitmask & 0x00ff);
+  cviReg = ReadReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL);
+  cviReg |= (uInt8) ((bitmask >> 7) & 0x0002);
+
+  WriteReg (pVdaaHW,pVdaa->channel,INTE_MSK,intMaskReg);
+  WriteReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL,cviReg);
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_ReadRingDetectStatus
+**
+** Description:
+** Reads ring detect/hook status
+**
+** Returns:
+**
+**
+*/
+
+int Vdaa_ReadRingDetectStatus (vdaaChanType *pVdaa,
+                               vdaaRingDetectStatusType *pStatus)
+{
+  uInt8 reg;
+
+  TRACEPRINT( pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  reg = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
+  pStatus->offhook = reg & 0x01;
+  pStatus->ringDetected = (reg & 0x4)>>2;
+  pStatus->onhookLineMonitor = (reg & 0x8)>>3;
+  pStatus->ringDetectedPos = (reg & 0x20)>>5;
+  pStatus->ringDetectedNeg = (reg & 0x40)>>6;
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_Init
+**
+** Description:
+** Initialize VDAA, load general config parameters
+**
+*/
+
+extern vdaa_General_Cfg Vdaa_General_Configuration;
+
+int Vdaa_Init (vdaaChanType_ptr *pVdaa,int size)
+{
+  uInt8 data;
+  int k;
+  int num_devices = 0;
+
+  TRACEPRINT( *pVdaa, "size = %d\n", size);
+
+  for (k=0; k<size; k++)
+  {
+
+    if(pVdaa[k]->channelType == PROSLIC)
+    {
+      continue;  /* Skip if we know this is a ProSLIC, else check the device out */
+    }
+
+    if (isVerifiedDAA(pVdaa[k]) == RC_CHANNEL_TYPE_ERR)
+    {
+      pVdaa[k]->channelEnable = FALSE;
+      pVdaa[k]->error = RC_CHANNEL_TYPE_ERR;
+      pVdaa[k]->channelType = UNKNOWN;
+      DEBUG_PRINT(pVdaa[k], "%sVDAA not supported on this device\n",LOGPRINT_PREFIX);
+      continue;
+    }
+    else
+    {
+      pVdaa[k]->channelType = DAA;
+    }
+
+    if (pVdaa[k]->channelEnable)
+    {
+      /*Try to write innocuous register to test SPI is working*/
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,PCMRX_CNT_LO,0x5A);
+      data = pVdaa[k]->ReadRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,PCMRX_CNT_LO);
+      if (data != 0x5A)
+      {
+        pVdaa[k]->error = RC_SPI_FAIL;
+        pVdaa[k]->channelEnable = FALSE;
+        DEBUG_PRINT(pVdaa[k], "%sVDAA %d not communicating\n",LOGPRINT_PREFIX,
+                    pVdaa[k]->channel);
+      }
+      else
+      {
+        num_devices++;
+      }
+    }
+  }
+
+  if(num_devices == 0)
+  {
+    DEBUG_PRINT(*pVdaa, "%sNo DAA devices detected\n", LOGPRINT_PREFIX);
+    return RC_SPI_FAIL;
+  }
+
+  for (k=0; k<size; k++)
+  {
+    if(pVdaa[k]->channelType != DAA)
+    {
+      continue;  /* Skip PROSLIC or UNDEFINED ports */
+    }
+    if (pVdaa[k]->channelEnable)
+    {
+
+      /* Apply General Configuration parameters */
+
+      /* No need to read-modify-write here since registers are in their reset state */
+      data = (Vdaa_General_Configuration.pwmm << 4) |
+             (Vdaa_General_Configuration.pwmEnable << 3);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,CTRL1, data);
+
+      data = (Vdaa_General_Configuration.inte << 7) | (Vdaa_General_Configuration.intp
+             << 6) | 0x03;
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,CTRL2, data);
+
+      data = (Vdaa_General_Configuration.hssm << 3);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,SMPL_CTRL, data);
+
+      data = (Vdaa_General_Configuration.iire << 4);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,INTL_CTRL1, data);
+
+      data = (Vdaa_General_Configuration.rcald << 4);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,RES_CALIB, data);
+
+      data = (Vdaa_General_Configuration.full2 << 4);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,AC_TERM_CTRL, data);
+
+      data = (Vdaa_General_Configuration.lvfd) | (Vdaa_General_Configuration.filt <<
+             1) |
+             (Vdaa_General_Configuration.foh << 5) | (Vdaa_General_Configuration.full << 7);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,DAA_CTRL5, data);
+
+      data = (Vdaa_General_Configuration.spim << 6);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,PCM_SPI_CTRL, data);
+
+      data = (Vdaa_General_Configuration.cvp) | (Vdaa_General_Configuration.cvs << 2);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,LN_VI_THRESH_INTE_CTRL,
+                          data);
+
+      data = (Vdaa_General_Configuration.gce << 1) | (Vdaa_General_Configuration.rg1
+             << 2);
+      pVdaa[k]->WriteRegX(pVdaa[k]->pVdaaHWX,pVdaa[k]->channel,SPRK_QNCH_CTRL, data);
+
+      /* Enable Lineside Device */
+      Vdaa_PowerupLineside(pVdaa[k]);
+    }
+  }
+  DEBUG_PRINT(*pVdaa,"%sDAA initialization completed\n",LOGPRINT_PREFIX);
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_ReadLinefeedStatus
+**
+** Description:
+** Read Status of Line Feed
+**
+** Returns:
+** RC_VDAA_ILOOP_OVLD if LCS >= 0x1F
+**      - no overload
+**
+*/
+
+int Vdaa_ReadLinefeedStatus (vdaaChanType *pVdaa,int8 *vloop, int16 *iloop)
+{
+  int16 regTemp = 0x1F;
+  uInt8 iloop_reg; /* REG 12[4:0] = Loop current*/
+
+  TRACEPRINT( pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+  regTemp &= ReadReg(pVdaaHW,pVdaa->channel,LSIDE_STAT);
+  iloop_reg = (uInt8)regTemp;
+  *iloop = (regTemp*LCS_SCALE_NUM) /
+           LCS_SCALE_DEN; /* Multiply the read result by 3.3mA/bit*/
+
+  *vloop = (int8) ReadReg(pVdaaHW,pVdaa->channel,LINE_VOLT_STAT);
+  if(*vloop & 0x80)
+  {
+    *vloop = ~(*vloop - 1)*(-1);
+  }
+
+  if (iloop_reg == 0x1F)
+  {
+    return RC_VDAA_ILOOP_OVLD;
+  }
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_GetInterrupts
+**
+** Description:
+** Get Interrupts
+**
+** Returns:
+** number of interrupts
+**
+*/
+
+int Vdaa_GetInterrupts (vdaaChanType *pVdaa,vdaaIntType *pIntData)
+{
+  uInt8 data = 0;
+  int j;
+  TRACEPRINT( pVdaa, "\n", NULL);
+  pIntData->number = 0;
+
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  data = ReadReg(pVdaaHW,pVdaa->channel,INTE_SRC);      /*Snapshot Interrupts*/
+  WriteReg(pVdaaHW,pVdaa->channel,INTE_SRC,~(data));      /*Clear interrupts*/
+
+  for (j=0; j<8; j++)
+  {
+    if (data &(1<<j))
+    {
+
+      pIntData->irqs[pIntData->number] =   j;
+      pIntData->number++;
+
+    }
+  }
+  data = ReadReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL);
+
+  if (data &(0x08))                   /*to determine if CVI Interrupt is set*/
+  {
+    pIntData->irqs[pIntData->number] =   CVI;
+    pIntData->number++;
+    data &= ~(0x08);
+    WriteReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL,data);
+
+  }
+
+  return pIntData->number;
+}
+
+/*
+** Function:  Vdaa_ClearInterrupts
+**
+** Description:
+** Clear Interrupts
+**
+** Returns:
+**
+**
+*/
+
+int Vdaa_ClearInterrupts (vdaaChanType *pVdaa)
+{
+  uInt8 data = 0;
+
+  TRACEPRINT( pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  WriteReg(pVdaaHW,pVdaa->channel,INTE_SRC,
+           0x00);    /* Clear interrupts in REG 4 by writing 0's*/
+
+  /*Clear CVI interrupt by writing 0 at REG 44[3]*/
+  data = ReadReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL);
+  WriteReg(pVdaaHW,pVdaa->channel,LN_VI_THRESH_INTE_CTRL,data&0xF7);
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_GetHookStatus
+**
+** Description:
+** Read VDAA Hook Status
+**
+** Return Values -
+**      VDAA_ONHOOK
+**      VDAA_OFFHOOK
+**      VDAA_ONHOOK_MONITOR
+**      RC_INVALID_HOOK_STATUS
+*/
+
+uInt8 Vdaa_GetHookStatus (vdaaChanType *pVdaa)
+{
+  uInt8 data;
+
+  TRACEPRINT( pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
+  data &= 0x09;  /* Look at only ONHM and OH */
+
+  if((data & 0x80)&&(data & 0x01))
+  {
+    return VDAA_ONHOOK_MONITOR;
+  }
+  else if (data & 0x01)
+  {
+    return VDAA_OFFHOOK;
+  }
+  else
+  {
+    return VDAA_ONHOOK;
+  }
+}
+
+/*
+** Function:  Vdaa_SetHookStatus
+**
+** Description:
+** Set VDAA Hook switch to ONHOOK, OFFHOOK,
+** or ONHOOK_MONITOR
+**
+*/
+
+int Vdaa_SetHookStatus (vdaaChanType *pVdaa,uInt8 newHookStatus)
+{
+  uInt8 data= 0 ;
+
+  TRACEPRINT( pVdaa, "hookstate = %u\n", (unsigned int) newHookStatus);
+
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  switch (newHookStatus)
+  {
+    case VDAA_DIG_LOOPBACK:
+      /*Setting REG6[4]=1,REG5[0]=0,REG5[3]=0*/
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
+      data |= 0x10;
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
+      data &= ~(0x09);
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
+      break;
+
+    case VDAA_ONHOOK:
+      /*Setting REG6[4]=0,REG5[0]=0,REG5[3]=0*/
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
+      data &= 0xF6;
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
+      data &= 0xEF;
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
+      break;
+
+    case VDAA_OFFHOOK:
+      /*Setting REG6[4]=0,REG5[0]=1,REG5[3]=0*/
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
+      data &= 0xF7;
+      data |= 0x01;
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
+      data &= 0xEF;
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
+      break;
+
+    case VDAA_ONHOOK_MONITOR:
+      /*Setting REG6[4]=0,REG5[0]=0,REG5[3]=1*/
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL1);
+      data &= 0xFE;
+      data |= 0x08;
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL1,data);
+      data = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL2);
+      data &= 0xEF;
+      WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,data);
+      break;
+
+    default:
+      return RC_UNSUPPORTED_OPTION;
+  }
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_SetLoopbackMode
+**
+** Description:
+** Loopback mode control
+**
+*/
+
+int Vdaa_SetLoopbackMode(vdaaChanType_ptr pVdaa, tLpbkMode lpbk_mode,
+                         tLpbkStatus lpbk_status)
+{
+  uInt8 regData;
+
+  TRACEPRINT(pVdaa, "lpbk_mode = %u lpbk_status = %d\n", (unsigned int) lpbk_mode,
+             (unsigned int) lpbk_status);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  switch(lpbk_mode)
+  {
+    case LPBK_NONE:
+      /* Disable all loopback types, regardless of lpbk_status */
+      regData = ReadReg(pVdaaHW,pVdaa->channel,CTRL1);
+      if(regData & 0x02)
+      {
+        WriteReg(pVdaaHW,pVdaa->channel,CTRL1, regData & ~(0x02));
+      }
+
+      regData = ReadReg(pVdaaHW,pVdaa->channel,DAA_CTRL3);
+      if(regData & 0x01)
+      {
+        WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL3,0);
+      }
+
+      regData = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
+      if(regData & 0x80)
+      {
+        WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL, regData & ~(0x80));
+      }
+      break;
+
+    case LPBK_IDL:
+      if(lpbk_status)
+      {
+        regData = ReadReg(pVdaaHW,pVdaa->channel,CTRL1);
+        WriteReg(pVdaaHW,pVdaa->channel,CTRL1, regData | 0x02);
+      }
+      else
+      {
+        regData = ReadReg(pVdaaHW,pVdaa->channel,CTRL1);
+        WriteReg(pVdaaHW,pVdaa->channel,CTRL1, regData & ~(0x02));
+      }
+      break;
+
+    case LPBK_DDL:
+      if(lpbk_status)
+      {
+        WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL3, 0x01);
+      }
+      else
+      {
+        WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL3, 0);
+      }
+      break;
+
+    case LPBK_PCML:
+      if(lpbk_status)
+      {
+        regData = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
+        WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL, regData | 0x80);
+      }
+      else
+      {
+        regData = ReadReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL);
+        WriteReg(pVdaaHW,pVdaa->channel,PCM_SPI_CTRL, regData & ~(0x80));
+      }
+      break;
+
+    default:
+      return RC_UNSUPPORTED_OPTION;
+  }
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_ADCCal
+**
+** Description:
+** This function calibrates the VDAA ADC manually
+**
+*/
+
+int Vdaa_ADCCal (vdaaChanType_ptr pVdaa, int32 size)
+{
+  uInt8 regTemp = 0;
+  int32 i;
+
+  TRACEPRINT(pVdaa, "size = %d\n", (int) size);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  for(i = 0; i < size; i++)
+  {
+    /* Clear the previous ADC Calibration data by toggling CALZ*/
+    regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL2);
+    regTemp |= 0x80;
+    WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
+    regTemp &= ~0x80;
+    WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
+
+    regTemp = ReadReg(pVdaaHW,pVdaa->channel,INTL_CTRL2); /*disable auto cal*/
+    regTemp |= 0x20;
+    WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
+
+    regTemp |= 0x40;                  /*initiate manual cal*/
+    WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
+    regTemp &= ~0x40;
+    WriteReg(pVdaaHW,pVdaa->channel,INTL_CTRL2,regTemp);
+    pVdaa++;
+  }
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_EnableWatchdog
+**
+** Description:
+** Enables watchdog timer
+**
+*/
+
+int Vdaa_EnableWatchdog(vdaaChanType_ptr pVdaa)
+{
+  uInt8 regTemp;
+
+  TRACEPRINT(pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2);
+  WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp | 0x10);
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_SetHybridEnable
+**
+** Description:
+** Enables watchdog timer
+**
+*/
+
+int Vdaa_SetHybridEnable(vdaaChanType_ptr pVdaa, int enable)
+{
+  uInt8 regTemp;
+  TRACEPRINT(pVdaa, "enable = %d\n", enable);
+
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  regTemp = ReadReg(pVdaaHW,pVdaa->channel,CTRL2);
+  if(enable)
+  {
+    WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp | 0x02);
+  }
+  else
+  {
+    WriteReg(pVdaaHW,pVdaa->channel,CTRL2,regTemp & ~(0x02));
+  }
+
+  return RC_NONE;
+}
+
+
+/*
+** Function:  Vdaa_SoftReset
+**
+** Description:
+** Execute soft reset
+**
+*/
+
+int Vdaa_SoftReset(vdaaChanType_ptr pVdaa)
+{
+  TRACEPRINT(pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  WriteReg(pVdaaHW,pVdaa->channel,CTRL1,0x80);
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_ReadFDTStatus
+**
+** Description:
+** Read FDT bit
+**
+** Returns:
+** 0 - Frame Not Detected
+** 1 - Frame Detected
+**
+*/
+
+int Vdaa_ReadFDTStatus(vdaaChanType_ptr pVdaa)
+{
+  TRACEPRINT(pVdaa, "\n", NULL);
+  return (ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV) & 0x40);
+}
+
+/*
+** Function:  Vdaa_PowerupLineside
+**
+** Description:
+** Power up lineside device
+**
+*/
+
+int Vdaa_PowerupLineside(vdaaChanType_ptr pVdaa)
+{
+  uInt8 data; 
+
+  TRACEPRINT(pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,0); /* Powerup lineside device */
+  /* We do a double read to give the front end time to power up and sync up with the system side.. */
+  data = ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV);
+  data = 0;
+  data = ReadReg(pVdaaHW,pVdaa->channel,LSIDE_REV);
+  pVdaa->deviceId->lsRev= ((data&0x3C)>>2);
+  data = pVdaa->ReadRegX(pVdaa->pVdaaHWX,pVdaa->channel,SYS_LINE_DEV_REV);
+  pVdaa->deviceId->lsType= ((data&~(0xF))>>4);
+
+  return RC_NONE;
+}
+
+/*
+** Function:  Vdaa_PowerdownLineside
+**
+** Description:
+** Power down lineside device
+**
+*/
+
+int Vdaa_PowerdownLineside(vdaaChanType_ptr pVdaa)
+{
+  TRACEPRINT(pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  WriteReg(pVdaaHW,pVdaa->channel,DAA_CTRL2,0x10);
+  return RC_NONE;
+}
+
+/*
+** Function: Vdaa_PrintDebugData
+**
+** Description:
+** Dump of VDAA register space
+**
+** Input Parameters:
+** pVdaa:       pointer to SiVoiceChanType or vdaaChanType
+**
+*/
+
+int Vdaa_PrintDebugData (vdaaChanType *pVdaa)
+{
+#ifdef ENABLE_DEBUG
+  int i;
+  for (i=0; i<60; i++)
+  {
+    LOGPRINT ("%sRegister %d = %X\n",LOGPRINT_PREFIX,i,ReadReg(pVdaaHW,
+              pVdaa->channel,i));
+  }
+#endif
+  return RC_NONE;
+}
+
+/*
+** Function: Vdaa_InitLineInUseCheck
+**
+** Description:
+** Set line in use test limits
+**
+** Input Parameters:
+** liuCfg:      pointer to vdaa_LIU_Config
+** minOnV:      minimum acceptable onhook voltage (below indicates parallel handset)
+** minOffV:     minimum acceptable offhook voltage (below indicates parallel handset)
+** minOffI:     minimum acceptable offhook loop current (below indicates parallel handset)
+**
+*/
+
+int Vdaa_InitLineInUseCheck(vdaa_LIU_Config *liuCfg, int8 minOnV, int8 minOffV,
+                            int16 minOffI)
+{
+  TRACEPRINT_NOCHAN("min0nV = %d minoffV = %d minOffI = %d\n", minOnV, minOffV,
+                    minOffI);
+  liuCfg->status = PAR_HANDSET_NOT_DETECTED;
+  liuCfg->min_onhook_vloop = minOnV;
+  liuCfg->min_offhook_vloop = minOffV;
+  liuCfg->min_offhook_iloop = minOffI;
+  return RC_NONE;
+}
+
+/*
+** Function: Vdaa_CheckForLineInUse
+**
+** Description:
+** Monitor LVCS to detect intrusion or parallel handset
+**
+** Input Parameters:
+** pVdaa:       pointer to SiVoiceChanType or vdaaChanType
+** liuCfg:      pointer to vdaa_LIU_Config
+**
+** Output Parameters:
+**
+** Return:
+** VDAA_ONHOOK    -   line is onhook
+** VDAA_OFFHOOK   -   line is offhook (in use)
+**
+*/
+
+uInt8 Vdaa_CheckForLineInUse(vdaaChanType *pVdaa, vdaa_LIU_Config *liuCfg)
+{
+  int8 vloop;
+  int16 iloop;
+
+  TRACEPRINT(pVdaa, "\n", NULL);
+  if(pVdaa->channelType != DAA)
+  {
+    return RC_IGNORE;
+  }
+
+  /* Check voltage and current */
+  Vdaa_ReadLinefeedStatus(pVdaa, &vloop,&iloop);
+  if(vloop < 0)
+  {
+    vloop *= -1;
+  }
+  liuCfg->measured_iloop = iloop;
+  liuCfg->measured_vloop = vloop;
+  liuCfg->status = PAR_HANDSET_NOT_DETECTED;
+
+  /* Read hookswitch status */
+  if(Vdaa_GetHookStatus(pVdaa) == VDAA_OFFHOOK)
+  {
+    if((vloop < liuCfg->min_offhook_vloop)||(iloop < liuCfg->min_offhook_iloop))
+    {
+      liuCfg->status = PAR_HANDSET_DETECTED;
+    }
+
+    return VDAA_OFFHOOK;
+  }
+  else
+  {
+    if(vloop < liuCfg->min_onhook_vloop)
+    {
+      liuCfg->status = PAR_HANDSET_DETECTED;
+    }
+
+    return VDAA_ONHOOK;
+  }
+}
+
diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/vdaa_constants.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/vdaa_constants.c
new file mode 100644
index 0000000..9c4606b
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/src/vdaa_constants.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0

+/*

+ * Si3217x ProSLIC API Configuration Tool Version 4.2.1

+ * Last Updated in API Release: 9.2.0

+ * source XML file: si3217x_FLBK_GDRV_constants.xml

+ *

+ * Auto generated file from configuration tool.

+ */

+

+#include "../inc/vdaa.h"

+

+vdaa_General_Cfg Vdaa_General_Configuration  = {

+    INTE_DISABLED,

+    INTE_ACTIVE_LOW,

+    RES_CAL_ENABLED,

+    FS_8KHZ,

+    FOH_128,

+    LVS_FORCE_ENABLED,

+    CVS_CURRENT,

+    CVP_ABOVE,

+    GCE_DISABLED,

+    IIR_DISABLED,

+    FULL2_ENABLED,

+    FULL_DISABLED,

+    FILT_HPF_200HZ,

+    RG1_DISABLED,

+    PWM_DELTA_SIGMA,

+    PWM_DISABLED,

+    SPIM_TRI_CS

+};

+

+vdaa_Country_Cfg Vdaa_Country_Presets[] ={

+    {

+    RZ_MAX,

+    DC_50,

+    AC_600,

+    DCV3_5,

+    MINI_10MA,

+    ILIM_DISABLED,

+    OHS_LESS_THAN_0_5MS,

+    HYBRID_ENABLED

+    },  /* COU_USA */

+    {

+    RZ_MAX,

+    DC_50,

+    AC_270__750_150,

+    DCV3_5,

+    MINI_10MA,

+    ILIM_ENABLED,

+    OHS_3MS,

+    HYBRID_ENABLED

+    },  /* COU_GERMANY */

+    {

+    RZ_MAX,

+    DC_50,

+    AC_200__680_100,

+    DCV3_5,

+    MINI_10MA,

+    ILIM_DISABLED,

+    OHS_LESS_THAN_0_5MS,

+    HYBRID_ENABLED

+    },  /* COU_CHINA */

+    {

+    RZ_MAX,

+    DC_50,

+    AC_220__820_120,

+    DCV3_2,

+    MINI_12MA,

+    ILIM_DISABLED,

+    OHS_26MS,

+    HYBRID_ENABLED

+    }   /* COU_AUSTRALIA */

+};

+

+vdaa_audioGain_Cfg Vdaa_audioGain_Presets[] ={

+    {

+    0,    /* mute */

+    XGA_GAIN,    /* xXGA2 */

+    0,    /* xXG2 */

+    XGA_GAIN,    /* xXGA3 */

+    0,    /* xXG3 */

+    64,    /* AxM */

+    0     /* cpEn */

+    },  /* AUDIO_GAIN_0DB */

+    {

+    0,    /* mute */

+    XGA_ATTEN,    /* xXGA2 */

+    4,    /* xXG2 */

+    XGA_GAIN,    /* xXGA3 */

+    0,    /* xXG3 */

+    64,    /* AxM */

+    0     /* cpEn */

+    },  /* AUDIO_ATTEN_4DB */

+    {

+    0,    /* mute */

+    XGA_ATTEN,    /* xXGA2 */

+    6,    /* xXG2 */

+    XGA_GAIN,    /* xXGA3 */

+    0,    /* xXG3 */

+    64,    /* AxM */

+    0     /* cpEn */

+    },  /* AUDIO_ATTEN_6DB */

+    {

+    0,    /* mute */

+    XGA_ATTEN,    /* xXGA2 */

+    11,    /* xXG2 */

+    XGA_GAIN,    /* xXGA3 */

+    0,    /* xXG3 */

+    64,    /* AxM */

+    0     /* cpEn */

+    }   /* AUDIO_ATTEN_11DB */

+};

+

+vdaa_Ring_Detect_Cfg Vdaa_Ring_Detect_Presets[] ={

+    {

+    RDLY_512MS,

+    RT__13_5VRMS_16_5VRMS,

+    12,    /* RMX */

+    RTO_1408MS,

+    RCC_640MS,

+    RNGV_DISABLED,

+    17,    /* RAS */

+    RFWE_HALF_WAVE,

+    RDI_BEG_END_BURST, 

+    RGDT_ACTIVE_LOW 

+    },  /* RING_DET_NOVAL_LOWV */

+    {

+    RDLY_512MS,

+    RT__40_5VRMS_49_5VRMS,

+    12,    /* RMX */

+    RTO_1408MS,

+    RCC_640MS,

+    RNGV_ENABLED,

+    17,    /* RAS */

+    RFWE_RNGV_RING_ENV,

+    RDI_BEG_END_BURST, 

+    RGDT_ACTIVE_LOW 

+    }   /* RING_DET_VAL_HIGHV */

+};

+

+vdaa_PCM_Cfg Vdaa_PCM_Presets[] ={

+    {

+    U_LAW,

+    PCLK_1_PER_BIT,

+    TRI_POS_EDGE

+    },  /* DAA_PCM_8ULAW */

+    {

+    A_LAW,

+    PCLK_1_PER_BIT,

+    TRI_POS_EDGE

+    },  /* DAA_PCM_8ALAW */

+    {

+    LINEAR_16_BIT,

+    PCLK_1_PER_BIT,

+    TRI_POS_EDGE

+    }   /* DAA_PCM_16LIN */

+};

+

+vdaa_Hybrid_Cfg Vdaa_Hybrid_Presets[] ={

+    {

+       0,    /* HYB1 */

+     254,    /* HYB2 */

+       0,    /* HYB3 */

+       1,    /* HYB4 */

+     255,    /* HYB5 */

+       1,    /* HYB6 */

+       0,    /* HYB7 */

+       0    /* HYB8 */

+    },  /* HYB_600_0_0_500FT_24AWG */

+    {

+       4,    /* HYB1 */

+     246,    /* HYB2 */

+     242,    /* HYB3 */

+       4,    /* HYB4 */

+     254,    /* HYB5 */

+     255,    /* HYB6 */

+       1,    /* HYB7 */

+     255    /* HYB8 */

+    },  /* HYB_270_750_150_500FT_24AWG */

+    {

+       4,    /* HYB1 */

+     245,    /* HYB2 */

+     243,    /* HYB3 */

+       7,    /* HYB4 */

+     253,    /* HYB5 */

+       0,    /* HYB6 */

+       1,    /* HYB7 */

+     255    /* HYB8 */

+    },  /* HYB_200_680_100_500FT_24AWG */

+    {

+       4,    /* HYB1 */

+     244,    /* HYB2 */

+     241,    /* HYB3 */

+       6,    /* HYB4 */

+     253,    /* HYB5 */

+     255,    /* HYB6 */

+       2,    /* HYB7 */

+     255    /* HYB8 */

+    }   /* HYB_220_820_120_500FT_24AWG */

+};

+