| /** \file vp880_init.c |
| * vp880_init.c |
| * |
| * This file contains the line and device initialization functions for |
| * the Vp880 device API. |
| * |
| * Copyright (c) 2011, Microsemi |
| * |
| * $Revision: 1.1.2.1.8.3 $ |
| * $LastChangedDate: 2012-01-03 10:13:15 -0600 (Tue, 03 Jan 2012) $ |
| */ |
| |
| #include "../includes/vp_api_cfg.h" |
| |
| #ifdef VP_CC_880_SERIES |
| |
| /* INCLUDES */ |
| #include "../../arch/uvb/vp_api_types.h" |
| #include "../includes/vp_api.h" |
| #include "../includes/vp_api_int.h" |
| #include "../includes/vp880_api.h" |
| #include "../vp880_api/vp880_api_int.h" |
| #include "../../arch/uvb/vp_hal.h" |
| #include "../../arch/uvb/sys_service.h" |
| |
| /**< Vp880 Initalization Function Prototypes */ |
| static VpStatusType Vp880Init(VpDevCtxType *pDevCtx); |
| |
| static VpStatusType |
| Vp880InitDevice( |
| VpDevCtxType *pDevCtx, |
| VpProfilePtrType pDevProfile, |
| VpProfilePtrType pAcProfile, |
| VpProfilePtrType pDcProfile, |
| VpProfilePtrType pRingProfile, |
| VpProfilePtrType pFxoAcProfile, |
| VpProfilePtrType pFxoCfgProfile); |
| |
| static VpStatusType Vp880DeviceReset(Vp880DeviceObjectType *pDevObj); |
| |
| static VpStatusType |
| Vp880InitLine( |
| VpLineCtxType *pLineCtx, |
| VpProfilePtrType pAcProfile, |
| VpProfilePtrType pDcFeedOrFxoCfgProfile, |
| VpProfilePtrType pRingProfile); |
| |
| static VpStatusType |
| Vp880InitProfile( |
| VpDevCtxType *pDevCtx, |
| VpProfileType type, |
| VpProfilePtrType pProfileIndex, |
| VpProfilePtrType pProfile); |
| |
| #ifdef VP880_FXS_SUPPORT |
| static void Vp880CopyDefaultFRProfile(Vp880DeviceObjectType *pDevObj); |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| /** |
| * VpMakeVp880DeviceObject() |
| * This function performs the main tasks of VpMakeDeviceObject() for Vp880 type |
| * of devices. |
| * |
| * Preconditions: |
| * Same as VpMakeDeviceObject(), and in addition the deviceType pointed to by |
| * pDevCtx should be Vp880 series type. |
| * |
| * Postconditions: |
| * VpAPI Function pointers for pDevCtx are initialized to Vp880 specific |
| * functions. This completes the function abstraction for "this" device. |
| */ |
| VpStatusType |
| VpMakeVp880DeviceObject( |
| VpDevCtxType *pDevCtx, /**< Device context to be initialized with function |
| * pointers |
| */ |
| Vp880DeviceObjectType *pDevObj) /**< Device object containing information |
| * for the device pointed to by pDevCtx |
| */ |
| { |
| VpMemSet(pDevObj, 0, sizeof(Vp880DeviceObjectType)); |
| pDevObj->staticInfo.maxChannels = VP880_MAX_NUM_CHANNELS; |
| |
| #ifdef VP_DEBUG |
| pDevObj->debugSelectMask = VP_OPTION_DEFAULT_DEBUG_SELECT; |
| #endif |
| |
| /* Initialize other elements in the device object */ |
| return VpMakeVp880DeviceCtx(pDevCtx, pDevObj); |
| } /* VpMakeVp880DeviceObject() */ |
| |
| /** |
| * VpMakeVp880DeviceCtx() |
| * This function initializes the device context to handle Vp880 functionality. |
| * |
| * Preconditions: |
| * This function should be called after initializing the device object. This |
| * function can be called more than once since it does not modify the contents |
| * of the device object. |
| * |
| * Postconditions: |
| * Initializes device context to be able to handle Vp780 functionality. |
| */ |
| VpStatusType |
| VpMakeVp880DeviceCtx( |
| VpDevCtxType *pDevCtx, /**< Device Context to be initialized */ |
| Vp880DeviceObjectType *pDevObj) /**< Device Object that has been already |
| * initialized |
| */ |
| { |
| uint8 channelCount, maxChan; |
| |
| /* All error checking of arguments performed in calling functions */ |
| |
| /* Initialize Device context */ |
| pDevCtx->pDevObj = pDevObj; |
| pDevCtx->deviceType = VP_DEV_880_SERIES; |
| |
| /* |
| * Initialize all of the line context pointers to null in the device context |
| */ |
| maxChan = pDevObj->staticInfo.maxChannels; |
| for (channelCount = 0; channelCount < maxChan; channelCount++) { |
| pDevCtx->pLineCtx[channelCount] = VP_NULL; |
| } |
| |
| /* Functions in apiInit.c */ |
| pDevCtx->funPtrsToApiFuncs.MakeLineObject = Vp880MakeLineObject; |
| pDevCtx->funPtrsToApiFuncs.InitDevice = Vp880InitDevice; |
| pDevCtx->funPtrsToApiFuncs.InitLine = Vp880InitLine; |
| pDevCtx->funPtrsToApiFuncs.ConfigLine = Vp880ConfigLine; |
| pDevCtx->funPtrsToApiFuncs.InitProfile = Vp880InitProfile; |
| |
| #ifdef VP880_FXS_SUPPORT |
| pDevCtx->funPtrsToApiFuncs.FreeRun = Vp880FreeRun; |
| #ifdef VP_CSLAC_SEQ_EN |
| pDevCtx->funPtrsToApiFuncs.InitRing = Vp880InitRing; |
| pDevCtx->funPtrsToApiFuncs.InitCid = Vp880InitCid; |
| pDevCtx->funPtrsToApiFuncs.InitMeter = VpCSLACInitMeter; |
| pDevCtx->funPtrsToApiFuncs.DtmfDigitDetected = VpCSLACDtmfDigitDetected; |
| #endif /* VP_CSLAC_SEQ_EN */ |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| #ifndef VP_REDUCED_API_IF |
| pDevCtx->funPtrsToApiFuncs.ClearResults = VpCSLACClearResults; |
| #endif /* VP_REDUCED_API_IF */ |
| |
| /* Functions in apicnt.c */ |
| pDevCtx->funPtrsToApiFuncs.SetLineState = Vp880SetLineState; |
| pDevCtx->funPtrsToApiFuncs.SetLineTone = Vp880SetLineTone; |
| #ifdef CSLAC_GAIN_RELATIVE |
| pDevCtx->funPtrsToApiFuncs.SetRelGain = Vp880SetRelGain; |
| #endif /* CSLAC_GAIN_RELATIVE */ |
| |
| #ifdef VP880_FXS_SUPPORT |
| pDevCtx->funPtrsToApiFuncs.SetRelayState = Vp880SetRelayState; |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| pDevCtx->funPtrsToApiFuncs.SendSignal = Vp880SendSignal; |
| #ifdef VP880_FXS_SUPPORT |
| pDevCtx->funPtrsToApiFuncs.SendCid = Vp880SendCid; |
| pDevCtx->funPtrsToApiFuncs.ContinueCid = Vp880ContinueCid; |
| pDevCtx->funPtrsToApiFuncs.StartMeter = VpCSLACStartMeter; |
| #endif /* VP880_FXS_SUPPORT */ |
| #endif /* VP_CSLAC_SEQ_EN */ |
| |
| pDevCtx->funPtrsToApiFuncs.SetOption = Vp880SetOption; |
| #ifndef VP880_SIMPLE_POLLED_MODE |
| pDevCtx->funPtrsToApiFuncs.VirtualISR = Vp880VirtualISR; |
| #endif /* VP880_SIMPLE_POLLED_MODE */ |
| |
| pDevCtx->funPtrsToApiFuncs.ApiTick = Vp880ApiTick; |
| |
| #if !defined(VP_REDUCED_API_IF) || defined(ZARLINK_CFG_INTERNAL) |
| pDevCtx->funPtrsToApiFuncs.LowLevelCmd = Vp880LowLevelCmd; |
| #endif /* !defined(VP_REDUCED_API_IF) || defined(ZARLINK_CFG_INTERNAL) */ |
| |
| pDevCtx->funPtrsToApiFuncs.DeviceIoAccess = Vp880DeviceIoAccess; |
| |
| /* Functions in apiQuery.c */ |
| pDevCtx->funPtrsToApiFuncs.GetEvent = Vp880GetEvent; |
| pDevCtx->funPtrsToApiFuncs.GetLineStatus = VpCSLACGetLineStatus; |
| pDevCtx->funPtrsToApiFuncs.GetDeviceStatus = Vp880GetDeviceStatus; |
| pDevCtx->funPtrsToApiFuncs.FlushEvents = Vp880FlushEvents; |
| pDevCtx->funPtrsToApiFuncs.GetResults = Vp880GetResults; |
| pDevCtx->funPtrsToApiFuncs.GetOption = Vp880GetOption; |
| |
| #ifdef VP880_INCLUDE_TESTLINE_CODE |
| /* Technically a "Query" function, but used only for Line Test purposes */ |
| pDevCtx->funPtrsToApiFuncs.GetRelayState = Vp880GetRelayState; |
| #endif /* VP880_INCLUDE_TESTLINE_CODE */ |
| |
| #if (VP_CC_DEBUG_SELECT & VP_DBG_ERROR) |
| pDevCtx->funPtrsToApiFuncs.RegisterDump = Vp880RegisterDump; |
| pDevCtx->funPtrsToApiFuncs.ObjectDump = Vp880ObjectDump; |
| #endif /* (VP_CC_DEBUG_SELECT & VP_DBG_ERROR) */ |
| |
| /* Functions in apiTestLine.c */ |
| #ifdef VP880_INCLUDE_TESTLINE_CODE |
| pDevCtx->funPtrsToApiFuncs.TestLineInt = Vp880TestLineInt; |
| pDevCtx->funPtrsToApiFuncs.TestLineCallback = Vp880TestLineCallback; |
| pDevCtx->funPtrsToApiFuncs.TestLine = Vp880TestLine; |
| #endif /* VP880_INCLUDE_TESTLINE_CODE */ |
| |
| /* Functions in apiCal.c */ |
| #if defined (VP880_FXS_SUPPORT) && defined (VP_CSLAC_RUNTIME_CAL_ENABLED) |
| #if !defined(VP_REDUCED_API_IF) || defined (VP_ENABLE_PROD_TEST) |
| /* |
| * The VpCalCodec() function is largely removed from the VP-API-II interface |
| * because it is not required. Once a system is calibrated, it does not need |
| * to be recalibrated AND actions performed in VpCalCodec() occur during |
| * VpInitDevice() (hence, no need for the application to directly call |
| * VpCalCodec()). However, for Production test purposes it is |
| * required. This is because backdoor methods are used to change the target |
| * voltage without intending to fully reinitialize the device. This can only |
| * be achieved by forcing battery calibration to repeat, which is done in |
| * the VpCalCodec() function (i.e., calling VpInitDevice() is not desired). |
| */ |
| pDevCtx->funPtrsToApiFuncs.CalCodec = Vp880CalCodec; |
| #endif /* !defined(VP_REDUCED_API_IF) || defined (VP_ENABLE_PROD_TEST) */ |
| pDevCtx->funPtrsToApiFuncs.CalLine = Vp880CalLine; |
| #endif /* defined (VP880_FXS_SUPPORT) && defined (VP_CSLAC_RUNTIME_CAL_ENABLED) */ |
| pDevCtx->funPtrsToApiFuncs.Cal = Vp880Cal; |
| |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /** |
| * VpMakeVp880LineObject() |
| * This function initializes a line context using the information that is |
| * passed. This function is like a C++ constructor. It initializes the passed |
| * line context and line object based on the paramters provided. The passed line |
| * object type should match with the type of device object type. See VP-API |
| * reference guide for more information. |
| * |
| * Preconditions: |
| * This function assumes device context has already been created and |
| * initialized. This function should only be called after downloading the boot |
| * image the device when applicable (like for VCP class of devices). |
| * |
| * Postconditions: |
| * This function initializes the line context/line object. Line related VP-API |
| * functions can be called after calling this function. |
| */ |
| VpStatusType |
| Vp880MakeLineObject( |
| VpTermType termType, |
| uint8 channelId, |
| VpLineCtxType *pLineCtx, |
| void *pVoidLineObj, |
| VpDevCtxType *pDevCtx) |
| { |
| Vp880LineObjectType *pLineObj = pVoidLineObj; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| |
| if (channelId >= pDevObj->staticInfo.maxChannels) { |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| VpMemSet(pLineObj, 0, sizeof(Vp880LineObjectType)); |
| #ifdef VP_DEBUG |
| pLineObj->debugSelectMask = VP_OPTION_DEFAULT_DEBUG_SELECT; |
| #endif |
| |
| switch (termType) { |
| #ifdef VP880_FXO_SUPPORT |
| case VP_TERM_FXO_GENERIC: |
| case VP_TERM_FXO_DISC: { |
| Vp880DeviceStateIntType chanMap[] = |
| {VP880_LINE0_IS_FXO, VP880_LINE1_IS_FXO}; |
| |
| /* |
| * At this point, it is only a recommendation. We'll adjust this |
| * when we determine the device type found in VpInitDevice() |
| */ |
| if (pDevObj->state & VP_DEV_INIT_CMP) { |
| if (chanMap[channelId] & pDevObj->stateInt) { |
| pLineObj->status |= VP880_IS_FXO; |
| } else { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_ERR_VTD_CODE; |
| } |
| } else { |
| pLineObj->status |= VP880_IS_FXO; |
| } |
| |
| pDevObj->stateInt |= ((channelId == 0) ? VP880_LINE0_LP : VP880_LINE1_LP); |
| |
| /* |
| * The "calDone" flag for the line object has to be set in order |
| * for VP_CAL_GET_SYSTEM_COEFF to return valid data. Otherwise, it |
| * would think the system is not 100% calibrated and return an error |
| * code. The FXO lines do not require calibration so this is the |
| * only opportuity to set this flag. |
| */ |
| pLineObj->calLineData.calDone = TRUE; |
| } |
| break; |
| #endif /* VP880_FXO_SUPPORT */ |
| |
| #ifdef VP880_FXS_SUPPORT |
| case VP_TERM_FXS_GENERIC: |
| case VP_TERM_FXS_ISOLATE: |
| case VP_TERM_FXS_SPLITTER: |
| pLineObj->status = VP880_INIT_STATUS; |
| pDevObj->stateInt &= ((channelId == 0) ? ~VP880_LINE0_LP : ~VP880_LINE1_LP); |
| break; |
| |
| #ifdef VP880_LP_SUPPORT |
| case VP_TERM_FXS_LOW_PWR: |
| case VP_TERM_FXS_ISOLATE_LP: |
| case VP_TERM_FXS_SPLITTER_LP: |
| pLineObj->status = VP880_INIT_STATUS; |
| pDevObj->stateInt |= ((channelId == 0) ? VP880_LINE0_LP : VP880_LINE1_LP); |
| break; |
| #endif /* VP880_LP_SUPPORT */ |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| default: |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_ERR_VTD_CODE; |
| } |
| |
| pLineCtx->pLineObj = pLineObj; |
| pLineCtx->pDevCtx = pDevCtx; |
| |
| pDevCtx->pLineCtx[channelId] = pLineCtx; |
| pLineObj->channelId = channelId; |
| pLineObj->termType = termType; |
| pLineObj->ecVal = ((channelId == 0) ? VP880_EC_CH1 : VP880_EC_CH2); |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| /* Everything else done by device/line specific functions */ |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /** |
| * Vp880Init |
| * This function initializes the device, and (contrary to InitDevice) does |
| * not initialize any channels. This function should be called internal to the |
| * API only. |
| * |
| * Preconditions: |
| * The device context must be of a Vp880 device type. |
| * |
| * Postconditions: |
| * This function returns a failure code if the clock configuration is not set |
| * correctly based on the device data set in InitDevice. |
| */ |
| VpStatusType |
| Vp880Init( |
| VpDevCtxType *pDevCtx) |
| { |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| |
| uint8 intMaskData[] = {0x7F, 0xFF}; |
| uint8 clkNotStable; |
| uint8 clkTestCount; |
| |
| VP_API_FUNC_INT(VpDevCtxType, pDevCtx, ("Vp880Init+")); |
| |
| /* |
| * If the MPI Bus gets out of sequence for any reason, a HW reset command |
| * will not work and this function may fail. To be sure a reset occurs, the |
| * following sequence is required. |
| */ |
| if(Vp880DeviceReset(pDevObj) != VP_STATUS_SUCCESS) { |
| VP_ERROR(VpDevCtxType, pDevCtx, ("Device Failed to Reset Properly")); |
| |
| VP_API_FUNC_INT(VpDevCtxType, pDevCtx, ("Vp880Init-")); |
| return VP_STATUS_FAILURE; |
| } |
| |
| /* |
| * Setup mclk. The MCLK mask set the mclk frequency, sets the mclk source |
| * (the MCLK pin or the PCLK pin), and sets the interrupt pin output drive |
| * mode (TTL or open collector) |
| */ |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_MCLK_CNT_WRT, VP880_MCLK_CNT_LEN, |
| &pDevObj->devProfileData.devCfg1); |
| |
| /* Setup the Clock Fail Interrupt */ |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_INT_MASK_WRT, VP880_INT_MASK_LEN, |
| intMaskData); |
| |
| /* |
| * Wait for the CFAIL bit to clear before proceding. If the CFAIL bit does |
| * not clear after several trys, give up and return an error condition. Wait |
| * between each read of the status register. |
| */ |
| clkNotStable = VP880_CFAIL_MASK; |
| clkTestCount = MAX_CFAIL_TEST; |
| while(clkNotStable && (--clkTestCount) != 0) { |
| VpSysWait(CFAIL_TEST_INTERVAL*10); |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_UL_SIGREG_RD, |
| VP880_UL_SIGREG_LEN, pDevObj->intReg); |
| clkNotStable = pDevObj->intReg[0] & VP880_CFAIL_MASK; |
| } |
| |
| /* |
| * The CFAIL bit did not clear so the part will not complete initialization. |
| * Return error status to indicate failure. |
| */ |
| if(clkNotStable) { |
| pDevObj->deviceEvents.faults |= VP_DEV_EVID_CLK_FLT; |
| |
| VP_ERROR(VpDevCtxType, pDevCtx, ("Device Failed to Reset Clock Fault")); |
| |
| VP_API_FUNC_INT(VpDevCtxType, pDevCtx, ("Vp880Init-")); |
| return VP_STATUS_FAILURE; |
| } |
| |
| /* Setup interrupts back to default */ |
| intMaskData[0] = 0xFF; /* Clear all Device Interrupt Masks */ |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_INT_MASK_WRT, VP880_INT_MASK_LEN, intMaskData); |
| |
| /* |
| * The PCM mask tells the device which clock edge to grab and xmit the |
| * PCM data on and also which clock period LSB of the PCM data starts on |
| */ |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_XR_CS_WRT, VP880_XR_CS_LEN, |
| &pDevObj->devProfileData.clockSlot); |
| |
| VP_API_FUNC_INT(VpDevCtxType, pDevCtx, ("Vp880Init-")); |
| return VP_STATUS_SUCCESS; |
| } /* Vp880Init */ |
| |
| /** |
| * Vp880DeviceReset |
| * This function resets the MPI buffer and HW reset of the device. The method |
| * for doing this depends on the silicon revision due to I/O1 driver |
| * requirements. |
| * |
| * Preconditions: |
| * None. |
| * |
| * Postconditions: |
| * The Device is reset, and I/O1 is in a safe condition. |
| */ |
| VpStatusType |
| Vp880DeviceReset( |
| Vp880DeviceObjectType *pDevObj) |
| { |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| uint8 mpiCmdData, deviceRcn; |
| VpStatusType status; |
| |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880DeviceReset+")); |
| |
| /* |
| * First, make sure the MPI buffer is cleared so we can write to the |
| * device correctly prior to HW reset. Also verify a valid RCN/PCN. |
| */ |
| if ((status = Vp880InitDevicePcnRcn(pDevObj, deviceId)) != VP_STATUS_SUCCESS) { |
| return status; |
| } |
| |
| deviceRcn = pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION]; |
| |
| if (deviceRcn >= VP880_REV_JE) { |
| mpiCmdData = VP880_IODATA_IO1; |
| VP_LINE_STATE(None, NULL, ("3. Write IODATA 0x%02X on Both Channels", |
| VP880_IODATA_IO1)); |
| |
| VpMpiCmdWrapper(deviceId, (VP880_EC_CH1 | VP880_EC_CH2), VP880_IODATA_REG_WRT, |
| VP880_IODATA_REG_LEN, &mpiCmdData); |
| VpSysWait(24); /* EMR's take 2-3 ms to open/close */ |
| } |
| |
| /* Proceed with normal device level reset and required delay */ |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_HW_RESET_WRT, 0, VP_NULL); |
| VpSysWait(20); |
| |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880DeviceReset-")); |
| |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /******************************************************************************* |
| * Vp880InitDevicePcnRcn() |
| * Read in the PCN so we will know what type of device specifically we |
| * are working with. This affects the max number of lines supported by the |
| * device as well as the type of lines (and may affect the line init) |
| * |
| * Note: EC value is not important for this command |
| * |
| * Arguments: |
| * pDevObj - |
| * deviceId - |
| * |
| * Preconditions: |
| * |
| * Postconditions: |
| ******************************************************************************/ |
| VpStatusType |
| Vp880InitDevicePcnRcn( |
| Vp880DeviceObjectType *pDevObj, |
| VpDeviceIdType deviceId) |
| { |
| uint8 devicePcn, deviceRcn; |
| |
| /* |
| * If Device has already been succesfully initialized, don't need to run |
| * this process. |
| */ |
| if (pDevObj->state & VP_DEV_INIT_CMP) { |
| return VP_STATUS_SUCCESS; |
| } |
| |
| VpCSLACClearMPIBuffer(deviceId); |
| |
| /* |
| * Read revision code |
| * If >= JA then force I/O as below |
| * Force I/O1 to '1', and wait for (if present) the external relay to |
| * open |
| */ |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_RCN_PCN_RD, VP880_RCN_PCN_LEN, |
| pDevObj->staticInfo.rcnPcn); |
| |
| devicePcn = pDevObj->staticInfo.rcnPcn[VP880_PCN_LOCATION]; |
| deviceRcn = pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION]; |
| |
| /* MPI Failure if the PCN and RCN are both 0x00 or 0xFF */ |
| if (((devicePcn == 0xFF) && (deviceRcn == 0xFF)) || |
| ((devicePcn == 0x00) && (deviceRcn == 0x00))) { |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS | VP_DEV_INIT_CMP); |
| |
| VP_ERROR(None, VP_NULL, ("Device Failed to Detect Revision/PCN Properly: 0x%02X 0x%02X", |
| deviceRcn, devicePcn)); |
| |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevicePcnRcn-")); |
| return VP_STATUS_FAILURE; |
| } |
| |
| /* |
| * Force the revision code to at least JE on devices that behave just |
| * like JE and later devices, but have earlier revisions. |
| * |
| * NOTE: The revision code is used by I/O control, Set Relay State, Line |
| * test and other. Be VERY CAREFULL changing this "rcn force" to make sure |
| * no other major area is broken. A global search and code review everywhere |
| * the RCN is evaluated is the minimum required before making such a change. |
| */ |
| if (((devicePcn == VP880_DEV_PCN_88536) || (devicePcn == VP880_DEV_PCN_88264)) |
| && (deviceRcn < VP880_REV_JE)) { |
| deviceRcn = VP880_REV_JE; |
| pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION] = VP880_REV_JE; |
| } |
| |
| if (deviceRcn < VP880_REV_VC) { |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS | VP_DEV_INIT_CMP); |
| |
| VP_ERROR(None, VP_NULL, ("Unsupported Silicon Revision %d", |
| pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION])); |
| |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevicePcnRcn-")); |
| return VP_STATUS_FAILURE; |
| } |
| |
| /* |
| * Verify that we recognize the device by limiting to the range of those supported in the |
| * Vp880PcnType table. If not recognized (although may be a valid PN) return an error because |
| * the API-II does not know how to handle it. More often, the error is occuring because the |
| * hardware cannot talk to the device. |
| */ |
| switch(devicePcn) { |
| #ifdef VP880_FXO_SUPPORT |
| case VP880_DEV_PCN_88010: /**< FXO Only Silicon */ |
| pDevObj->stateInt |= VP880_LINE0_IS_FXO; |
| #endif /* VP880_FXO_SUPPORT */ |
| |
| #if defined (VP880_FXS_SUPPORT) && defined (VP880_TRACKER_SUPPORT) |
| case VP880_DEV_PCN_88111: /* FXS-Tracker */ |
| case VP880_DEV_PCN_88116: /* FXS-Tracker - Wideband */ |
| case VP880_DEV_PCN_88131: /* FXS-Tracker */ |
| case VP880_DEV_PCN_88136: /* FXS-Tracker - Wideband */ |
| #endif /* (VP880_FXS_SUPPORT) && defined (VP880_TRACKER_SUPPORT) */ |
| pDevObj->staticInfo.maxChannels = 1; |
| pDevObj->stateInt |= VP880_IS_SINGLE_CHANNEL; |
| break; |
| |
| #if defined (VP880_TRACKER_SUPPORT) || defined (VP880_FXO_SUPPORT) |
| case VP880_DEV_PCN_88311: /* FXO/FXS-Tracker */ |
| case VP880_DEV_PCN_88331: /* FXO/FXS-Tracker */ |
| pDevObj->stateInt |= VP880_LINE1_IS_FXO; |
| #endif /* (VP880_TRACKER_SUPPORT) || defined (VP880_FXO_SUPPORT) */ |
| |
| #ifdef VP880_FXS_SUPPORT |
| #ifdef VP880_TRACKER_SUPPORT |
| case VP880_DEV_PCN_88211: /* 2FXS-Tracker */ |
| case VP880_DEV_PCN_88216: /* 2FXS-Tracker - Wideband */ |
| case VP880_DEV_PCN_88231: /* 2FXS-Tracker */ |
| case VP880_DEV_PCN_88236: /* 2FXS-Tracker - Wideband */ |
| case VP880_DEV_PCN_88506: /* 2FXS-Tracker - Wideband Split Package*/ |
| case VP880_DEV_PCN_88536: /* 2FXS-Tracker - Wideband, IP Block */ |
| #endif /* VP880_TRACKER_SUPPORT */ |
| |
| #ifdef VP880_ABS_SUPPORT |
| case VP880_DEV_PCN_88221: /* 2FXS-ABS */ |
| case VP880_DEV_PCN_88226: /* 2FXS-ABS - Wideband */ |
| case VP880_DEV_PCN_88241: /* 2FXS-ABS */ |
| case VP880_DEV_PCN_88246: /* 2FXS-ABS - Wideband */ |
| case VP880_DEV_PCN_88264: /* 2FXS-ABS - Wideband, ZSI */ |
| |
| case VP880_DEV_PCN_88286_QFN: /* 2FXS-ABS, HV, WB, No Test Load */ |
| case VP880_DEV_PCN_88266_QFN: /* 2FXS-ABS, LV, WB, No Test Load */ |
| #endif /* VP880_ABS_SUPPORT */ |
| #endif /* VP880_FXS_SUPPORT */ |
| pDevObj->staticInfo.maxChannels = 2; |
| pDevObj->stateInt &= ~VP880_IS_SINGLE_CHANNEL; |
| break; |
| |
| default: |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS | VP_DEV_INIT_CMP); |
| VP_ERROR(None, VP_NULL, ("Revision/PCN Unknown")); |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevicePcnRcn-")); |
| return VP_STATUS_FAILURE; |
| } |
| |
| if (devicePcn & VP880_TRACKER_MASK) { |
| #if defined (VP880_TRACKER_SUPPORT) && defined (VP880_FXS_SUPPORT) |
| /* Mark as non-ABS device type */ |
| pDevObj->stateInt &= ~VP880_IS_ABS; |
| #endif /* (VP880_TRACKER_SUPPORT) && defined (VP880_FXS_SUPPORT) */ |
| } else { |
| if (devicePcn == VP880_DEV_PCN_88010) { |
| #ifdef VP880_FXO_SUPPORT |
| /* FXO only devices */ |
| pDevObj->stateInt |= VP880_IS_FXO_ONLY; |
| #endif /* VP880_FXO_SUPPORT */ |
| } else { |
| #ifdef VP880_ABS_SUPPORT |
| /* Last choice is ABS type */ |
| pDevObj->stateInt |= VP880_IS_ABS; |
| #endif /* VP880_ABS_SUPPORT */ |
| } |
| } |
| |
| /* |
| * Check for High Voltage Device and line test switch |
| * Currently high voltage and test switch go hand in hand but may not in |
| * the future that is why there are two bits but only a test for one. |
| */ |
| if ((devicePcn & VP880_HV_MASK) == VP880_HV_MASK) { |
| pDevObj->stateInt |= VP880_IS_HIGH_VOLTAGE; |
| |
| /* All HV devices support Line Test */ |
| pDevObj->stateInt |= VP880_IS_TEST_CAPABLE; |
| |
| if ((devicePcn != VP880_DEV_PCN_88506) && (devicePcn != VP880_DEV_PCN_88286_QFN)) { |
| pDevObj->stateInt |= VP880_HAS_TEST_LOAD_SWITCH; |
| } |
| } else { |
| /* Le88266 also supports Line Test but is LV */ |
| if ((devicePcn == VP880_DEV_PCN_88264) || |
| (devicePcn == VP880_DEV_PCN_88266_QFN) || |
| ((devicePcn == VP880_DEV_PCN_88226) && (deviceRcn > VP880_REV_VC))) { |
| pDevObj->stateInt |= VP880_IS_TEST_CAPABLE; |
| } |
| pDevObj->stateInt &= ~VP880_IS_HIGH_VOLTAGE; |
| pDevObj->stateInt &= ~VP880_HAS_TEST_LOAD_SWITCH; |
| } |
| |
| #ifdef VP880_ALWAYS_USE_INTERNAL_TEST_TERMINATION |
| /* If this option is defined, we will treat this device as if it has no |
| * physical test load. The internal test termination only works for |
| * revisions newer than VC, so ignore this override if it can't be used */ |
| if (deviceRcn > VP880_REV_VC) { |
| pDevObj->stateInt &= ~VP880_HAS_TEST_LOAD_SWITCH; |
| } |
| #endif /* VP880_ALWAYS_USE_INTERNAL_TEST_TERMINATION */ |
| |
| #ifdef VP_ENABLE_PROD_TEST |
| /* Workaround to enable LM Production Tests */ |
| /* |
| * The HV flag is incorrectly set (actually) but done so because earlier |
| * Line Test used this flag for determing Line Test Capabilities. Later |
| * Low Voltage silicon that supported Line Testing of course voided this |
| * rule requiring a new flag that specifically indicates Test Capable or not |
| * (hence - VP880_IS_TEST_CAPABLE). To be fully compatible, both flags must |
| * be set. |
| * |
| * Note that these settings SHOULD NOT be enabled for normal production |
| * purposes. Although it enables some amount of line testing (sufficient to |
| * measure some key parameters in the Appliations lab), test performance and |
| * accuracy is not gauranteed. Only a very limited number of tests from the |
| * VeriVoice Line Test Suite are used. Other tests may not run at all or |
| * run into a system lockup condition. |
| */ |
| pDevObj->stateInt |= (VP880_IS_HIGH_VOLTAGE | VP880_IS_TEST_CAPABLE); |
| #endif /* VP_ENABLE_PROD_TEST */ |
| |
| /* Check for Wideband Mode support */ |
| if ((devicePcn == VP880_DEV_PCN_88506) || |
| (devicePcn == VP880_DEV_PCN_88286_QFN) || |
| (devicePcn == VP880_DEV_PCN_88266_QFN) || |
| ((devicePcn & VP880_IS_IT_WB) == VP880_IS_IT_WB)) { |
| pDevObj->stateInt |= VP880_WIDEBAND; |
| } |
| |
| /* Check for Cal Circuit and relay protection */ |
| if (VP880_REV_VC == deviceRcn) { |
| if (pDevObj->stateInt & VP880_IS_SINGLE_CHANNEL) { |
| /* none of the single channel rev 2 devices have a cal circuit */ |
| pDevObj->stateInt &= ~VP880_HAS_CALIBRATE_CIRCUIT; |
| } else { |
| pDevObj->stateInt |= VP880_HAS_CALIBRATE_CIRCUIT; |
| } |
| } else { |
| /* all other revs should have cal circuit and require relay protection */ |
| pDevObj->stateInt |= VP880_HAS_CALIBRATE_CIRCUIT; |
| pDevObj->stateInt |= VP880_RLY_PROT_REQ; |
| } |
| |
| if ((devicePcn == VP880_DEV_PCN_88506) || (devicePcn == VP880_DEV_PCN_88536)) { |
| pDevObj->stateInt |= VP880_RLY_PROT_REQ; |
| } |
| |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /** |
| * Vp880InitDevice |
| * This function initializes the device and all lines associated with this |
| * device (if line profiles are passed to this function). The device profile |
| * passed must be valid otherwise an error code is returned and the device |
| * remains in it's previously initialized state. |
| * |
| * Preconditions: |
| * None (device context is not NULL and is of Vp880 type, which is handled in |
| * higher level software) |
| * |
| * Postconditions: |
| * This device is initialized to the configuration specified in the device |
| * profile, and the FXS lines associated with this device are initialized by the |
| * FXS specific AC, DC, and Ringing profiles passed, and the FXO lines |
| * associated with this device are initialized by the FXO specific AC and Config |
| * profiles passed. If the FXO/FXS profiles are all NULL, then only the device |
| * initialization occurs. This function returns an error code if the device |
| * profile trying to be used for initialization is VP_PTABLE_NULL (either |
| * passed or by a non-initialized index). |
| */ |
| VpStatusType |
| Vp880InitDevice( |
| VpDevCtxType *pDevCtx, |
| VpProfilePtrType pDevProfile, /**< The profile pointer for the device |
| * configuration parameters |
| */ |
| VpProfilePtrType pAcProfile, /**< The profile pointer (or index) for |
| * the AC characteristic to apply to the |
| * FXS lines |
| */ |
| VpProfilePtrType pDcProfile, /**< The profile pointer (or index) for |
| * the DC characteristic to apply to the |
| * FXS lines |
| */ |
| VpProfilePtrType pRingProfile, /**< The profile pointer (or index) for |
| * the Ringing characteristic to apply to |
| * the FXS lines |
| */ |
| VpProfilePtrType pFxoAcProfile, /**< The profile pointer (or index) for |
| * the AC characteristic to apply to the |
| * FXO lines |
| */ |
| VpProfilePtrType pFxoCfgProfile)/**< The profile pointer for the FXO |
| * specific supervision paramaters. |
| */ |
| { |
| VpLineCtxType *pLineCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| Vp880LineObjectType *pLineObj; |
| uint8 ecVal = pDevObj->ecVal; |
| |
| #ifdef VP880_FXS_SUPPORT |
| uint8 ecAll = (VP880_EC_CH1 | VP880_EC_CH2); |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| uint8 maxChan, chan, pcn, rcn, mpiData; |
| VpProfilePtrType pDevProf; |
| |
| #if defined (VP880_TRACKER_SUPPORT) && defined (VP880_FXS_SUPPORT) |
| uint8 intSwParam[VP880_INT_SWREG_PARAM_LEN] = {0x5C, 0x4B, 0xC4, 0x4B, 0xC4, 0x4B}; |
| #endif /* defined (VP880_TRACKER_SUPPORT) && defined (VP880_FXS_SUPPORT) */ |
| |
| #ifdef VP880_ABS_SUPPORT |
| uint8 systemConfig = 0; |
| #endif /* VP880_ABS_SUPPORT */ |
| |
| #ifdef VP880_CURRENT_LIMIT |
| uint8 intSwParamLimit[VP880_INT_SWREG_PARAM_LEN] = {0xB2, 0x00, 0xB1, 0x00, 0x60, 0x40}; |
| #endif /* VP880_CURRENT_LIMIT */ |
| |
| VpStatusType status = VP_STATUS_SUCCESS; |
| |
| int profIndex = VpGetProfileIndex(pDevProfile); |
| |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice+")); |
| |
| /* |
| * Get Profile Index returns -1 if the profile passed is a pointer or |
| * of VP_PTABLE_NULL type. Otherwise it returns the index |
| */ |
| |
| if (profIndex < 0) { |
| /* |
| * A pointer is passed or VP_PTABLE_NULL. If it's a pointer, make |
| * sure the content is valid for the profile type. |
| */ |
| if (pDevProfile != VP_PTABLE_NULL) { |
| if(VpVerifyProfileType(VP_PROFILE_DEVICE, pDevProfile) != TRUE) { |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice-")); |
| return VP_STATUS_ERR_PROFILE; |
| } |
| } else { |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| pDevObj->state &= ~VP_DEV_INIT_IN_PROGRESS; |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice-")); |
| return VP_STATUS_ERR_PROFILE; |
| } |
| pDevProf = pDevProfile; |
| } else if (profIndex < VP_CSLAC_DEV_PROF_TABLE_SIZE) { |
| pDevProf = pDevObj->devProfileTable.pDevProfileTable[profIndex]; |
| if (pDevProf == VP_PTABLE_NULL) { |
| return VP_STATUS_ERR_PROFILE; |
| } |
| } else { |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice-")); |
| return VP_STATUS_ERR_PROFILE; |
| } |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| /* Initialize the API's device status variables */ |
| if (pDevObj->state & VP_DEV_INIT_CMP) { |
| pDevObj->state = (VP_DEV_WARM_REBOOT | VP_DEV_INIT_IN_PROGRESS); |
| } else { |
| pDevObj->state = VP_DEV_INIT_IN_PROGRESS; |
| } |
| pDevObj->timeStamp = 0; |
| |
| /* Initialize the API's device dynamic variables */ |
| pDevObj->dynamicInfo.lastChan = 0; |
| pDevObj->dynamicInfo.bat1Fault = FALSE; |
| pDevObj->dynamicInfo.bat2Fault = FALSE; |
| pDevObj->dynamicInfo.bat3Fault = FALSE; |
| pDevObj->dynamicInfo.clkFault = FALSE; |
| |
| /* |
| * Reset the internal state information except for possibly previously |
| * loaded calibration values. |
| */ |
| pDevObj->stateInt &= (VP880_SYS_CAL_COMPLETE | VP880_DEVICE_CAL_COMPLETE); |
| |
| pDevObj->devProfileData.profVersion = (uint8)(pDevProf[VP_PROFILE_VERSION]); |
| |
| pDevObj->devProfileData.pcmClkRate = |
| (uint16)(((pDevProf[VP880_DEV_PROFILE_PCLK_MSB] << 8) & 0xFF00) |
| | (pDevProf[VP880_DEV_PROFILE_PCLK_LSB] & 0x00FF)); |
| |
| pDevObj->devProfileData.devCfg1 = (uint8)(pDevProf[VP880_DEV_PROFILE_DEVCFG1]); |
| pDevObj->devProfileData.clockSlot = (uint8)(pDevProf[VP880_DEV_PROFILE_CLOCK_SLOT]); |
| pDevObj->devProfileData.systemConfig = (uint8)(pDevProf[VP880_DEV_PROFILE_SYSTEM_CFG]); |
| |
| pDevObj->devProfileData.tickRate = |
| (uint16)(((pDevProf[VP880_DEV_PROFILE_TICKRATE_MSB] << 8) & 0xFF00) |
| | (pDevProf[VP880_DEV_PROFILE_TICKRATE_LSB] & 0x00FF)); |
| |
| #ifdef VP880_FXS_SUPPORT |
| if (pDevProf[VP880_DEV_PROFILE_OPERATIONAL_CFG] & VP880_DEV_PROFILE_PK_PWR_MGMT) { |
| pDevObj->devProfileData.peakManagement = TRUE; |
| } else { |
| pDevObj->devProfileData.peakManagement = FALSE; |
| } |
| |
| if (pDevProf[VP880_DEV_PROFILE_OPERATIONAL_CFG] & VP880_DEV_PROFILE_LOW_VOLT_OVERRIDE) { |
| pDevObj->devProfileData.lowVoltOverride = TRUE; |
| } else { |
| pDevObj->devProfileData.lowVoltOverride = FALSE; |
| } |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| /* |
| * Support only version of the profile that contain the switching |
| * regulator parameters. Otherwise, we really don't know what to do... |
| */ |
| if (pDevProf[VP_PROFILE_VERSION] < VP_CSLAC_DEV_PROFILE_VERSION_SW_CONFIG) { |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS | VP_DEV_INIT_CMP); |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| VP_ERROR(None, VP_NULL, ("Unsupported Device Profile Version")); |
| |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice Unsupported Profile Version-")); |
| return VP_STATUS_ERR_PROFILE; |
| } else { |
| VpMemCpy(pDevObj->swParams, &pDevProf[VP880_DEV_PROFILE_SWITCHER_CMD+1], |
| VP880_REGULATOR_PARAM_LEN); |
| } |
| |
| /* Initialize device */ |
| /* |
| * If not successful, the Clock Fail bit did not clear so return error code |
| */ |
| if ((status = Vp880Init(pDevCtx)) != VP_STATUS_SUCCESS) { |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS | VP_DEV_INIT_CMP); |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880Init Init Failure-")); |
| return status; |
| } |
| pcn = pDevObj->staticInfo.rcnPcn[VP880_PCN_LOCATION]; |
| rcn = pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION]; |
| |
| maxChan = pDevObj->staticInfo.maxChannels; |
| |
| #ifdef VP880_LP_SUPPORT |
| /* |
| * Make initial assumption that the device has lines such that low power |
| * mode is in affect. The line controls will change as necessary. |
| */ |
| pDevObj->stateInt |= (VP880_LINE0_LP | VP880_LINE1_LP); |
| #else /* VP880_LP_SUPPORT */ |
| pDevObj->stateInt &= ~(VP880_LINE0_LP | VP880_LINE1_LP); |
| #endif /* VP880_LP_SUPPORT */ |
| |
| /* Check if device is Tracker and if so, initialize for FXS functionality */ |
| if (pcn & VP880_TRACKER_MASK) { |
| #if defined (VP880_TRACKER_SUPPORT) && defined (VP880_FXS_SUPPORT) |
| uint8 icr3Vals[VP880_ICR3_LEN] = {0x00, 0x00, 0x00, 0x00}; |
| |
| /* Initialize Tracker device sensitve items */ |
| /* |
| * Configure the Switcher for Flyback or Buckboost per device |
| * profile. If the device is in Buckboost mode, config the internal |
| * switcher |
| */ |
| if (pDevProf[VP_PROFILE_VERSION] >= VP_CSLAC_DEV_PROFILE_VERSION_INT_SW_CONFIG) { |
| /* Write the internal switcher parameters */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_INT_SWREG_PARAM_WRT, |
| VP880_INT_SWREG_PARAM_LEN, (uint8 *)&pDevProf[VP880_DEV_PROFILE_TRACKER_INT_SW_REG]); |
| } else { |
| /* Write the default internal parameters */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_INT_SWREG_PARAM_WRT, |
| VP880_INT_SWREG_PARAM_LEN, intSwParam); |
| } |
| |
| if (pDevProf[VP_PROFILE_VERSION] >= VP_CSLAC_DEV_PROFILE_VERSION_INT_SW_CONFIG_FR) { |
| /* Cache the internal switcher parameters for free run mode */ |
| VpMemCpy(pDevObj->intSwParamsFR, &pDevProf[VP880_DEV_PROFILE_TRACKER_INT_SW_REG + |
| VP880_INT_SWREG_PARAM_LEN], VP880_INT_SWREG_PARAM_LEN); |
| } else { |
| Vp880CopyDefaultFRProfile(pDevObj); |
| } |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_PARAM_WRT, |
| VP880_REGULATOR_PARAM_LEN, pDevObj->swParams); |
| VpMemCpy(pDevObj->swParamsCache, pDevObj->swParams, VP880_REGULATOR_PARAM_LEN); |
| |
| /* Device is reset, so ch1 and 2 are at same values for ICR's |
| * NOTE: This also has to be done in VpInitLine() due to SW |
| * Reset. |
| */ |
| icr3Vals[VP880_ICR3_LINE_CTRL_INDEX] = VP880_ICR3_VREF_CTRL; |
| icr3Vals[VP880_ICR3_LINE_CTRL_INDEX+1] = VP880_ICR3_VREF_CTRL; |
| VpMpiCmdWrapper(deviceId, ecAll, VP880_ICR3_WRT, VP880_ICR3_LEN, icr3Vals); |
| VP_LINE_STATE(None, NULL, ("Init: ICR3 0x%02X 0x%02X 0x%02X 0x%02X Ch %d", |
| icr3Vals[0], icr3Vals[1], icr3Vals[2], icr3Vals[3], ecAll)); |
| |
| /* |
| * Wait at least 5ms before turning the switchers on for Vref to |
| * stabilize. We'll wait 10ms to be safe. |
| */ |
| VpSysWait(80); |
| |
| /* |
| * Enable the switchers in low power. The power mode is changed as |
| * needed during normal operation. |
| */ |
| mpiData = VP880_SWY_LP | VP880_SWZ_LP; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_CTRL_WRT, |
| VP880_REGULATOR_CTRL_LEN, &mpiData); |
| #endif /* (VP880_TRACKER_SUPPORT) && defined (VP880_FXS_SUPPORT) */ |
| } else { |
| #ifdef VP880_ABS_SUPPORT |
| if (pDevProf[VP_PROFILE_VERSION] >= |
| VP_CSLAC_DEV_PROFILE_VERSION_INT_SW_CONFIG) { |
| |
| /* Write the internal switcher parameters */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_INT_SWREG_PARAM_WRT, |
| VP880_INT_SWREG_PARAM_LEN, (uint8 *)&pDevProf[VP880_DEV_PROFILE_ABS_INT_SW_REG]); |
| /* Extract Y/Z Voltages. "0" if not set by Profile Wizard */ |
| pDevObj->yVolt = pDevProf[VP880_ABS_DEV_PROFILE_YVOLT]; |
| pDevObj->zVolt = pDevProf[VP880_ABS_DEV_PROFILE_ZVOLT]; |
| } |
| |
| if (pDevProf[VP_PROFILE_VERSION] >= VP_CSLAC_DEV_PROFILE_VERSION_INT_SW_CONFIG_FR) { |
| /* Cache the internal switcher parameters for free run mode */ |
| VpMemCpy(pDevObj->intSwParamsFR, &pDevProf[VP880_DEV_PROFILE_ABS_INT_SW_REG + |
| VP880_INT_SWREG_PARAM_LEN], VP880_INT_SWREG_PARAM_LEN); |
| } else { |
| /* No free run timing available -> save default ones */ |
| Vp880CopyDefaultFRProfile(pDevObj); |
| } |
| |
| /* |
| * Make sure lines are in disconnect state (recover from shutdown) |
| * even if there are no line contexts associated with this device. |
| */ |
| mpiData = VP880_SS_DISCONNECT; |
| VpMpiCmdWrapper(deviceId, ecAll, VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, &mpiData); |
| |
| mpiData = VP880_SWY_OFF; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_CTRL_WRT, |
| VP880_REGULATOR_CTRL_LEN, &mpiData); |
| |
| #ifdef VP880_CURRENT_LIMIT |
| /* Implement a user compile option to limit the switcher power */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_INT_SWREG_PARAM_WRT, |
| VP880_INT_SWREG_PARAM_LEN, intSwParamLimit); |
| #endif /* VP880_CURRENT_LIMIT */ |
| |
| if (!(pDevObj->stateInt & VP880_IS_FXO_ONLY)) { |
| systemConfig = (pDevObj->devProfileData.systemConfig & VP880_ABS_CFG_MASK); |
| |
| #ifdef VP880_AUTO_BAT_DETECT |
| if ((status = Vp880AutoBatDetect(pDevObj, |
| &pDevProf[VP880_DEV_PROFILE_SWITCHER_CMD+1])) != VP_STATUS_SUCCESS) { |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS | VP_DEV_INIT_CMP); |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice Exit Error %d-", status)); |
| return status; |
| } |
| #else /* VP880_AUTO_BAT_DETECT */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_PARAM_WRT, |
| VP880_REGULATOR_PARAM_LEN, pDevObj->swParams); |
| VpMemCpy(pDevObj->swParamsCache, pDevObj->swParams, VP880_REGULATOR_PARAM_LEN); |
| |
| mpiData = VP880_SWY_LP | VP880_SWZ_LP; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_CTRL_WRT, |
| VP880_REGULATOR_CTRL_LEN, &mpiData); |
| |
| if (systemConfig != VP880_ABS_CFG_SLAVE) { |
| VpSysWait(240); /* 125us * 240 = 30ms */ |
| VpSysWait(160); /* 125us * 160 = 20ms */ |
| if (systemConfig == VP880_ABS_CFG_SINGLE) { |
| mpiData = VP880_SWY_MP | VP880_SWZ_MP; |
| } else { /* systemConfig == VP880_ABS_CFG_MASTER */ |
| mpiData = VP880_SWY_HP | VP880_SWZ_HP; |
| } |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_CTRL_WRT, |
| VP880_REGULATOR_CTRL_LEN, &mpiData); |
| } |
| #endif /* VP880_AUTO_BAT_DETECT */ |
| } |
| #endif /* VP880_ABS_SUPPORT */ |
| } |
| |
| /* |
| * No matter how they were provided, cache the internal switcher parameters |
| * and the switcher parameters. |
| */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_INT_SWREG_PARAM_RD, |
| VP880_INT_SWREG_PARAM_LEN, pDevObj->intSwParams); |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_PARAM_RD, |
| VP880_REGULATOR_PARAM_LEN, pDevObj->swParamsCache); |
| VpMemCpy(pDevObj->swParams, pDevObj->swParamsCache, |
| VP880_REGULATOR_PARAM_LEN); |
| |
| /* Initialize each channel */ |
| for (chan = 0; chan < maxChan; chan++) { |
| /* |
| * For Init Line to work, the device cannot be non-initialized because |
| * the init line function tries to set the line state. Therefore, |
| * temporarily set the device init flag to TRUE then immediately after |
| * line init, set back to FALSE until device init is complete |
| */ |
| pLineCtx = pDevCtx->pLineCtx[chan]; |
| if (pLineCtx != VP_NULL) { |
| pLineObj = pLineCtx->pLineObj; |
| |
| if (pLineObj->status & VP880_IS_FXO) { |
| status = Vp880InitLine(pLineCtx, pFxoAcProfile, pFxoCfgProfile, |
| VP_PTABLE_NULL); |
| } else { |
| status = Vp880InitLine(pLineCtx, pAcProfile, pDcProfile, |
| pRingProfile); |
| #ifdef VP880_INCLUDE_TESTLINE_CODE |
| /* initialize the calibration coeffs */ |
| pDevObj->calOffsets[chan].nullOffset = 0; |
| pDevObj->calOffsets[chan].vabOffset = 0; |
| pDevObj->calOffsets[chan].vahOffset = 0; |
| pDevObj->calOffsets[chan].vbhOffset = 0; |
| #endif /* VP880_INCLUDE_TESTLINE_CODE */ |
| } |
| |
| if (status != VP_STATUS_SUCCESS) { |
| pDevObj->state &= |
| ~(VP_DEV_INIT_IN_PROGRESS | VP_DEV_INIT_CMP); |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice Exit Error %d-", |
| status)); |
| return status; |
| } |
| } else { |
| /* |
| * If the per-channel configuration register did not get set, we |
| * have to set it in order for calibration to run consistently. |
| * Note that the Auto-System-State Control bit in the System State |
| * Configuration Register is the same for both FXS and FXO lines. |
| */ |
| mpiData = VP880_AUTO_SSC_DIS; |
| VpMpiCmdWrapper(deviceId, (VP880_EC_CH1 | VP880_EC_CH2), |
| VP880_SS_CONFIG_WRT, VP880_SS_CONFIG_LEN, &mpiData); |
| } |
| } |
| |
| status = VpImplementDefaultSettings(pDevCtx, VP_NULL); |
| |
| /* |
| * This clears the Init Line Events and any other erroneous event that |
| * may have been created due to initialization |
| */ |
| Vp880FlushEvents(pDevCtx); |
| |
| #ifdef VP880_INCLUDE_TESTLINE_CODE |
| /* |
| * This clears the Test structure |
| */ |
| pDevObj->currentTest.prepared = FALSE; |
| pDevObj->currentTest.testState = -1; |
| pDevObj->currentTest.testId = VP_NUM_TEST_IDS; |
| #endif /* VP880_INCLUDE_TESTLINE_CODE */ |
| |
| if (status == VP_STATUS_SUCCESS) { |
| if (pDevObj->stateInt & VP880_DEVICE_CAL_COMPLETE) { |
| VP_CALIBRATION(None, VP_NULL, ("Calibration Previously Complete: Device 0x%08lX RCN %d", |
| pDevObj->stateInt, rcn)); |
| pDevObj->state &= ~VP_DEV_IN_CAL; |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS); |
| pDevObj->deviceEvents.response |= VP_DEV_EVID_DEV_INIT_CMP; |
| |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_BAT_CALIBRATION_WRT, |
| VP880_BAT_CALIBRATION_LEN, pDevObj->calData.abvData.switcherAdjust[0]); |
| |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH2, VP880_BAT_CALIBRATION_WRT, |
| VP880_BAT_CALIBRATION_LEN, pDevObj->calData.abvData.switcherAdjust[1]); |
| } else { |
| #ifdef VP_CSLAC_RUNTIME_CAL_ENABLED |
| VP_CALIBRATION(None, VP_NULL, ("Cal Required: Device 0x%08lX RCN %d", |
| pDevObj->stateInt, rcn)); |
| |
| pDevObj->state |= VP_DEV_IN_CAL; |
| pDevObj->calData.calDeviceState = VP880_CAL_INIT; |
| |
| if (pDevObj->stateInt & VP880_IS_ABS) { /* Start for ABS Device */ |
| #ifdef VP880_ABS_SUPPORT |
| if ((systemConfig != VP880_ABS_CFG_SLAVE) && (Vp880SetCalFlags(pDevObj) == TRUE)) { |
| VP_CALIBRATION(None, VP_NULL, ("NOT Running Slave Mode Device 0x%08lX RCN %d", |
| pDevObj->stateInt, rcn)); |
| Vp880CalCodecInt(pDevCtx); |
| } else { |
| VP_CALIBRATION(None, VP_NULL, ("Slave Mode OR Cal Flags = FALSE Device 0x%08lX RCN %d", |
| pDevObj->stateInt, rcn)); |
| |
| pDevObj->state &= ~VP_DEV_IN_CAL; |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS); |
| pDevObj->deviceEvents.response |= VP_DEV_EVID_DEV_INIT_CMP; |
| } |
| #endif /* VP880_ABS_SUPPORT */ |
| } else { /* Start for Tracker Device if JE (JA 8827x) silicon */ |
| #ifdef VP880_TRACKER_SUPPORT |
| if (rcn >= VP880_REV_JE) { |
| pDevObj->state |= VP_DEV_ABV_CAL; |
| Vp880CalCodecInt(pDevCtx); |
| } else { |
| pDevObj->state &= ~VP_DEV_IN_CAL; |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS); |
| pDevObj->deviceEvents.response |= VP_DEV_EVID_DEV_INIT_CMP; |
| } |
| #endif /* VP880_TRACKER_SUPPORT */ |
| } |
| #else /* VP_CSLAC_RUNTIME_CAL_ENABLED */ |
| VP_CALIBRATION(None, VP_NULL, ("\n\rCal Required, Disabled at Compile: Device 0x%08lX RCN %d", |
| pDevObj->stateInt, rcn)); |
| pDevObj->state &= ~VP_DEV_IN_CAL; |
| pDevObj->state &= ~(VP_DEV_INIT_IN_PROGRESS); |
| pDevObj->deviceEvents.response |= VP_DEV_EVID_DEV_INIT_CMP; |
| #endif /* VP_CSLAC_RUNTIME_CAL_ENABLED */ |
| } |
| } |
| |
| /* |
| * ZSI devices can't have TX Timeslot = 0. So initialize the channels to |
| * [tx, rx] -> channel 0 = [1, 1], channel 1 = [2, 2] |
| */ |
| if ((pcn == VP880_DEV_PCN_88536) || (pcn == VP880_DEV_PCN_88264)) { |
| uint8 txTimeSlot = 0; |
| uint8 rxTimeSlot = 1; |
| |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_TX_TS_WRT, VP880_TX_TS_LEN, |
| &txTimeSlot); |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH1, VP880_RX_TS_WRT, VP880_RX_TS_LEN, |
| &rxTimeSlot); |
| |
| txTimeSlot = 1; |
| rxTimeSlot = 2; |
| |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH2, VP880_TX_TS_WRT, VP880_TX_TS_LEN, |
| &txTimeSlot); |
| VpMpiCmdWrapper(deviceId, VP880_EC_CH2, VP880_RX_TS_WRT, VP880_RX_TS_LEN, |
| &rxTimeSlot); |
| } |
| |
| /* |
| * Success, Failure, or Calibration started -- we're not in "InitDevice" |
| * function anymore. So normal rules apply. |
| */ |
| pDevObj->state |= VP_DEV_INIT_CMP; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| VP_API_FUNC_INT(None, VP_NULL, ("Vp880InitDevice Exit Normal: State 0x%04X Event 0x%04X-", |
| pDevObj->state, pDevObj->deviceEvents.response)); |
| return status; |
| } /* Vp880InitDevice */ |
| |
| /** |
| * Vp880InitLine |
| * This function initializes a line of a device with the specified parameters |
| * and API default values. It is a "Line Reset". |
| * |
| * Preconditions: |
| * The device associated with this line must be initialized. |
| * |
| * Postconditions: |
| * The line pointed to be the line context passed is initialized with the |
| * profile data specified. This function returns the success code if the device |
| * associated with this line is initialized. |
| */ |
| VpStatusType |
| Vp880InitLine( |
| VpLineCtxType *pLineCtx, |
| VpProfilePtrType pAcProfile, /**< Pointer to AC coefficient data or |
| * profile index to be applied to this line. |
| */ |
| |
| VpProfilePtrType pDcOrFxoProfile, /**< Pointer to DC Feed (FXS) or Cfg |
| * (FX0) profile or profile index to be |
| * applied to this line. |
| */ |
| |
| VpProfilePtrType pRingProfile) /**< Pointer to Ringing profile or profile |
| * index to apply to this line |
| */ |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| |
| uint8 channelId = pLineObj->channelId; |
| uint8 ecValMap[] = {VP880_EC_CH1, VP880_EC_CH2}; |
| uint8 ecVal = ecValMap[channelId]; |
| |
| uint8 alwaysOn[VP880_CADENCE_TIMER_LEN] = {0x3F, 0xFF, 0x00, 0x00}; |
| uint8 opFunc[VP880_OP_FUNC_LEN] = {VP880_ENABLE_LOADED_COEFFICIENTS}; |
| |
| #ifdef VP880_FXS_SUPPORT |
| uint8 defaultRingParams[VP880_RINGER_PARAMS_LEN] = { |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| VpProfileDataType dcDefaultProf[] = { |
| 0x00, 0x01, 0x01, 0x0A, 0x00, 0x08, 0xC2, 0x1B, 0x84, 0xB3, 0x05, 0xC6, |
| 0x13, 0x08 |
| }; |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| #ifdef VP880_FXO_SUPPORT |
| VpProfileDataType fxoDefaultProf[] = |
| { |
| /* FXO/Dialing Profile */ |
| 0x00, 0xFE, 0x00, 0x12, 0x00, 0x00, 0x00, 0x27, 0x00, 0x28, 0x00, 0x78, |
| 0x0C, 0x08, 0x00, 0x28, 0xEB, 0x79, 0x04, 0x03, 0x26, 0x3A |
| }; |
| |
| uint8 fxoCidLine; |
| #endif /* VP880_FXO_SUPPORT */ |
| |
| VpStatusType status = VP_STATUS_SUCCESS; |
| uint8 mpiData; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| |
| /* Proceed if device state is either in progress or complete */ |
| if (pDevObj->state & (VP_DEV_INIT_CMP | VP_DEV_INIT_IN_PROGRESS)) { |
| } else { |
| return VP_STATUS_DEV_NOT_INITIALIZED; |
| } |
| |
| /* |
| * Do not proceed if the device calibration is in progress. This could |
| * damage the device. |
| */ |
| if (pDevObj->state & VP_DEV_IN_CAL) { |
| return VP_STATUS_DEV_NOT_INITIALIZED; |
| } |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| pLineObj->ecVal = ecVal; |
| pLineObj->status &= ~VP880_INIT_COMPLETE; |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| VpMemSet(pLineObj->intSequence, 0, VP880_INT_SEQ_LEN); |
| |
| #ifdef VP880_FXS_SUPPORT |
| pLineObj->callerId.status = VP_CID_RESET_VALUE; |
| pLineObj->suspendCid = FALSE; |
| |
| pLineObj->pRingingCadence = VP_PTABLE_NULL; |
| pLineObj->pCidProfileType1 = VP_PTABLE_NULL; |
| #endif /* VP880_FXS_SUPPORT */ |
| #endif /* VP_CSLAC_SEQ_EN */ |
| |
| pLineObj->status &= ~(VP880_BAD_LOOP_SUP); |
| |
| /* Initialize cached transmit and receive gains for SetRelGain to 1.0. */ |
| pLineObj->gain.gxInt = 0x4000; |
| pLineObj->gain.grInt = 0x4000; |
| |
| /* Inititialize API line state variables */ |
| if (pLineObj->status & VP880_IS_FXO) { |
| #ifdef VP880_FXO_SUPPORT |
| pLineObj->lineState.currentState = VP_LINE_FXO_LOOP_OPEN; |
| pLineObj->lineState.previous = VP_LINE_FXO_LOOP_OPEN; |
| #endif /* VP880_FXO_SUPPORT */ |
| } else { |
| #ifdef VP880_FXS_SUPPORT |
| pLineObj->lineState.currentState = VP_LINE_DISCONNECT; |
| pLineObj->lineState.previous = VP_LINE_DISCONNECT; |
| pLineObj->lineState.usrCurrent = VP_LINE_DISCONNECT; |
| #endif /* VP880_FXS_SUPPORT */ |
| } |
| |
| /* Force a line state check and update hook information */ |
| pLineObj->lineState.condition = VP_CSLAC_STATUS_INVALID; |
| |
| #ifdef VP880_FXS_SUPPORT |
| pLineObj->dpStruct.hookSt = FALSE; |
| pLineObj->dpStruct2.hookSt = FALSE; |
| |
| VpInitDP(&pLineObj->dpStruct); |
| VpInitDP(&pLineObj->dpStruct2); |
| |
| pLineObj->internalTestTermApplied = FALSE; |
| |
| /* Set the cached ICR values to device reset conditions. */ |
| VpMemSet(pLineObj->icr1Values, 0, VP880_ICR1_LEN); |
| VpMemSet(pLineObj->icr2Values, 0, VP880_ICR2_LEN); |
| VpMemSet(pLineObj->icr3Values, 0, VP880_ICR3_LEN); |
| VpMemSet(pLineObj->icr4Values, 0, VP880_ICR4_LEN); |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| #ifdef VP880_LP_SUPPORT |
| pLineObj->leakyLineCnt = 0; /* Used only for LP Mode */ |
| |
| if (VpIsLowPowerTermType(pLineObj->termType) == TRUE) { |
| /* |
| * Manually Force the ICR values for LPM-Disconnect since we have no |
| * idea the status of the other line. |
| */ |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Updating Cached ICR Values for LPM on Channel %d", channelId)); |
| |
| pLineObj->icr1Values[0] = 0x0F; |
| pLineObj->icr1Values[2] = 0xC0; |
| |
| pLineObj->icr2Values[0] = 0xCC; |
| pLineObj->icr2Values[1] = 0x4C; |
| pLineObj->icr2Values[2] = 0x2C; |
| pLineObj->icr2Values[3] = 0x58; |
| |
| pLineObj->icr3Values[0] = 0x31; |
| pLineObj->icr3Values[1] = 0x01; |
| |
| pLineObj->icr4Values[2] = 0x0E; |
| pLineObj->icr4Values[3] = 0x0E; |
| |
| pLineObj->status |= VP880_LOW_POWER_EN; |
| pDevObj->stateInt |= ((channelId == 0) ? VP880_LINE0_LP : VP880_LINE1_LP); |
| } |
| #endif /* VP880_LP_SUPPORT */ |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| VpMemSet(&pLineObj->cadence, 0, sizeof(VpSeqDataType)); |
| #endif /* VP_CSLAC_SEQ_EN */ |
| |
| /* Force a codec update */ |
| pLineObj->codec = VP_NUM_OPTION_CODEC_TYPE_IDS; |
| |
| #ifdef VP880_FXS_SUPPORT |
| /* It is possible that CalCodec set ABS calibration values in ICR6 before |
| * this point, so read these from the device */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR6_RD, VP880_ICR6_LEN, pLineObj->icr6Values); |
| |
| /* |
| * Workaround for I/O1 relay driver. Problem is the I/O1 pin does not have |
| * proper voltage clamps to protect against normal voltage spikes that |
| * occur as a result of transitioning to Input or Open Drain on a driven |
| * relay coil. So this workaround will check to see if the pin is currently |
| * being used to close an external relay, and force it open. Then it has |
| * to wait for 3ms for the relay to fully open (coil to fully discharge). |
| */ |
| if ((pDevObj->stateInt & VP880_RLY_PROT_REQ) |
| && ((pLineObj->termType == VP_TERM_FXS_ISOLATE) |
| || (pLineObj->termType == VP_TERM_FXS_ISOLATE_LP) |
| || (pLineObj->termType == VP_TERM_FXS_SPLITTER))) { |
| |
| if((pLineObj->termType == VP_TERM_FXS_ISOLATE) || |
| (pLineObj->termType == VP_TERM_FXS_ISOLATE_LP)) { |
| Vp880SetRelayState(pLineCtx, VP_RELAY_NORMAL); |
| } else { |
| Vp880SetRelayState(pLineCtx, VP_RELAY_RESET); |
| } |
| |
| /* Wait for relay coil to fully discharge */ |
| VpSysWait(24); |
| } |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| /* |
| * Operating Conditions - Remove all loopbacks, connect TX/RX PCM Hwy |
| * Note that TX/RX PCM Highway is set when Set Linestate function is |
| * called. |
| */ |
| pLineObj->opCond[0] = VP880_NORMAL_OP_COND_MODE; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_OP_COND_WRT, VP880_OP_COND_LEN, |
| pLineObj->opCond); |
| |
| /* Operating Functions - Use loaded coefficients */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_OP_FUNC_WRT, VP880_OP_FUNC_LEN, |
| opFunc); |
| |
| /* Disable the internal device cadencer .. done in the API */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_CADENCE_TIMER_WRT, |
| VP880_CADENCE_TIMER_LEN, alwaysOn); |
| |
| /* Start the channel out in the standby state or loop open (if FXO) */ |
| if (pLineObj->status & VP880_IS_FXO) { |
| #ifdef VP880_FXO_SUPPORT |
| pLineObj->lineTimers.type = VP_CSLAC_FXO_TIMER; |
| /* |
| * InitTimerVars has to know the timer type but called before |
| * Set Line State. If set line state starts any timers, calling |
| * InitTimerVars would disable those causing possible initialization |
| * issues. |
| */ |
| InitTimerVars(pLineCtx); |
| |
| /* Disable auto system state control |
| * NOTE: NEVER enable the Auto-Thermal Fault disconnect in the silicon |
| * because the silicon is too fast for the VP-API-II. It would be possible |
| * to get a thermal fault, have the silicon disable the line, and have |
| * the thermal fault go away all before the VP-API-II sees it. In that |
| * condition, the line will be disabled without the application being |
| * aware of it. |
| */ |
| mpiData = VP880_AUTO_SSC_DIS; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_SS_CONFIG_WRT, VP880_SS_CONFIG_LEN, &mpiData); |
| |
| if (pLineObj->termType == VP_TERM_FXO_DISC) { |
| fxoCidLine = VP880_IODATA_IO3; |
| } else { |
| fxoCidLine = VP880_FXO_CID_LINE; |
| } |
| |
| mpiData &= ~VP880_IODIR_IO1_MASK; |
| mpiData = (VP880_IODIR_IO1_OUTPUT | (fxoCidLine << 1)); |
| |
| #ifdef VP880_CLARE_RINGING_DETECT |
| mpiData |= VP880_IODIR_EXPDT_MASK; /* Ringing detector on IO4 */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_IODIR_REG_WRT, VP880_IODIR_REG_LEN, &mpiData); |
| #endif /* VP880_CLARE_RINGING_DETECT */ |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| pLineObj->digitGenStruct.dtmfOnTime = VP_FXO_DTMF_ON_DEFAULT; |
| pLineObj->digitGenStruct.dtmfOffTime = VP_FXO_DTMF_OFF_DEFAULT; |
| pLineObj->digitGenStruct.breakTime = VP_FXO_PULSE_BREAK_DEFAULT; |
| pLineObj->digitGenStruct.makeTime = VP_FXO_PULSE_MAKE_DEFAULT; |
| pLineObj->digitGenStruct.flashTime = VP_FXO_FLASH_HOOK_DEFAULT; |
| pLineObj->digitGenStruct.dpInterDigitTime = VP_FXO_INTERDIG_DEFAULT; |
| pLineObj->digitGenStruct.dtmfHighFreqLevel[0] = 0x1C; |
| pLineObj->digitGenStruct.dtmfHighFreqLevel[1] = 0x32; |
| pLineObj->digitGenStruct.dtmfLowFreqLevel[0] = 0x1C; |
| pLineObj->digitGenStruct.dtmfLowFreqLevel[1] = 0x32; |
| #endif /* VP_CSLAC_SEQ_EN */ |
| |
| if (pDcOrFxoProfile == VP_NULL) { |
| status = Vp880ConfigLine(pLineCtx, pAcProfile, fxoDefaultProf, VP_PTABLE_NULL); |
| } else { |
| status = Vp880ConfigLine(pLineCtx, pAcProfile, pDcOrFxoProfile, VP_PTABLE_NULL); |
| } |
| |
| if (status != VP_STATUS_SUCCESS) { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return status; |
| } |
| /* Activate Codec and enable Supervision */ |
| /* |
| * Set to Loop Open. Set current state to Loop Close in order to force line |
| * state function to change to Loop Open. Otherwise, no changes are made |
| * since it thinks device is already set correctly. |
| */ |
| pLineObj->lineState.currentState = VP_LINE_FXO_LOOP_CLOSE; |
| Vp880SetLineStateInt(pLineCtx, VP_LINE_FXO_LOOP_OPEN); |
| pLineObj->lineState.usrCurrent = VP_LINE_FXO_LOOP_OPEN; |
| #endif /* VP880_FXO_SUPPORT */ |
| } else { |
| #ifdef VP880_FXS_SUPPORT |
| /* |
| * LPM supported on HV-Tracker devices only. Note that the HV check for |
| * LPM support ignores if there is an application level LV override. |
| * The override occurs because customers want a LV (low cost) design, |
| * but are given only HV silicon. |
| */ |
| if ((pDevObj->stateInt & VP880_IS_ABS) || (!(pDevObj->stateInt & VP880_IS_HIGH_VOLTAGE))) { |
| if (VpIsLowPowerTermType(pLineObj->termType)) { |
| pLineObj->termType = VP_TERM_FXS_GENERIC; |
| pDevObj->stateInt &= ~VP880_LINE0_LP; |
| pDevObj->stateInt &= ~VP880_LINE1_LP; |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_ERR_VTD_CODE; |
| } |
| } |
| |
| pLineObj->lineTimers.type = VP_CSLAC_FXS_TIMER; |
| /* |
| * InitTimerVars has to know the timer type but called before |
| * Set Line State. If set line state starts any timers, calling |
| * InitTimerVars would disable those causing possible initialization |
| * issues. |
| */ |
| InitTimerVars(pLineCtx); |
| |
| /* |
| * Enable Auto Bat Switch (ABS), Disable Auto-Battery Shutdown (Tracker) |
| * and disable Auto State Control (both). |
| * NOTE: NEVER enable the Auto-Thermal Fault disconnect in the silicon |
| * because the silicon is too fast for the VP-API-II. It would be possible |
| * to get a thermal fault, have the silicon disable the line, and have |
| * the thermal fault go away all before the VP-API-II sees it. In that |
| * condition, the line will be disabled without the application being |
| * aware of it. |
| */ |
| mpiData = VP880_AUTO_SSC_DIS; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_SS_CONFIG_WRT, |
| VP880_SS_CONFIG_LEN, &mpiData); |
| |
| /* Complete all other non device senstive items */ |
| |
| /* Initialize default values for Ringing */ |
| VpMemCpy(pLineObj->ringingParams, defaultRingParams, |
| VP880_RINGER_PARAMS_LEN); |
| |
| pLineObj->status &= ~(VP880_UNBAL_RINGING); |
| |
| if (pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION] > VP880_REV_VC) { |
| uint8 converterCfg[VP880_CONV_CFG_LEN]; |
| |
| /* Set the pcm buffer update rate based on the tickrate */ |
| if(pDevObj->devProfileData.tickRate <=160) { |
| converterCfg[0] = VP880_CC_8KHZ_RATE; |
| pDevObj->txBufferDataRate = VP880_CC_8KHZ_RATE; |
| |
| } else if(pDevObj->devProfileData.tickRate <=320){ |
| converterCfg[0] = VP880_CC_4KHZ_RATE; |
| pDevObj->txBufferDataRate = VP880_CC_4KHZ_RATE; |
| |
| } else if(pDevObj->devProfileData.tickRate <=640){ |
| converterCfg[0] = VP880_CC_2KHZ_RATE; |
| pDevObj->txBufferDataRate = VP880_CC_2KHZ_RATE; |
| |
| } else if(pDevObj->devProfileData.tickRate <=1280){ |
| converterCfg[0] = VP880_CC_1KHZ_RATE; |
| pDevObj->txBufferDataRate = VP880_CC_1KHZ_RATE; |
| } else { |
| converterCfg[0] = VP880_CC_500HZ_RATE; |
| pDevObj->txBufferDataRate = VP880_CC_500HZ_RATE; |
| } |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_CONV_CFG_WRT, |
| VP880_CONV_CFG_LEN, converterCfg); |
| |
| pDevObj->devMode[0] |= VP880_DEV_MODE_TEST_DATA; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_DEV_MODE_WRT, |
| VP880_DEV_MODE_LEN, pDevObj->devMode); |
| } |
| |
| #ifdef VP880_CURRENT_LIMIT |
| pLineObj->icr2Values[VP880_ICR2_SWY_CTRL_INDEX] |= VP880_ICR2_SWY_LIM_CTRL; |
| pLineObj->icr2Values[VP880_ICR2_SWY_CTRL_INDEX+1] &= ~VP880_ICR2_SWY_LIM_CTRL; |
| #endif /* VP880_CURRENT_LIMIT */ |
| |
| #ifdef VP880_TRACKER_SUPPORT |
| if (!(pDevObj->stateInt & VP880_IS_ABS)) { |
| if (VpIsLowPowerTermType(pLineObj->termType) == FALSE) { |
| pLineObj->lineTimers.timers.timer[VP_LINE_DISCONNECT_EXIT] = |
| (MS_TO_TICKRATE(VP880_SPEEDUP_HOLD_TIME, |
| pDevObj->devProfileData.tickRate)) | VP_ACTIVATE_TIMER; |
| |
| /* Initialize the Disconnect Exit Timer State */ |
| pLineObj->discTimerExitState = 0; |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Chan %d Setting VP_LINE_DISCONNECT_EXIT time to %d ms (VP880_SPEEDUP_HOLD_TIME) at time %d", |
| pLineObj->channelId, VP880_SPEEDUP_HOLD_TIME, pDevObj->timeStamp)); |
| |
| pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION] |= |
| VP880_ICR1_LINE_BIAS_OVERRIDE; |
| pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION+1] &= |
| (VP880_ICR1_LINE_BIAS_OVERRIDE | VP880_ICR1_LINE_BIAS_OVERRIDE_NORM); |
| |
| pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION+1] |= |
| VP880_ICR1_LINE_BIAS_OVERRIDE_NORM; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR1_WRT, VP880_ICR1_LEN, |
| pLineObj->icr1Values); |
| |
| pLineObj->icr2Values[VP880_ICR2_SENSE_INDEX] |= |
| (VP880_ICR2_DAC_SENSE | VP880_ICR2_FEED_SENSE); |
| pLineObj->icr2Values[VP880_ICR2_SENSE_INDEX+1] &= ~VP880_ICR2_DAC_SENSE; |
| pLineObj->icr2Values[VP880_ICR2_SENSE_INDEX+1] |= VP880_ICR2_FEED_SENSE; |
| } |
| |
| /* Tracker Workaround: |
| * Enable VRef while in Disconnect. Otherwise the Switcher will |
| * shutdown because it thinks it's not needed. |
| */ |
| pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX] |= VP880_ICR3_VREF_CTRL; |
| pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX+1] |= VP880_ICR3_VREF_CTRL; |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR3_WRT, VP880_ICR3_LEN, |
| pLineObj->icr3Values); |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Line Init: ICR3 0x%02X 0x%02X 0x%02X 0x%02X Ch %d", |
| pLineObj->icr3Values[0], pLineObj->icr3Values[1], |
| pLineObj->icr3Values[2], pLineObj->icr3Values[3], channelId)); |
| |
| #ifndef VP880_CURRENT_LIMIT |
| /* Eliminate use of 50V clamp for all conditions */ |
| pLineObj->icr2Values[VP880_ICR2_SWY_CTRL_INDEX] |= |
| (VP880_ICR2_SWY_LIM_CTRL1 | VP880_ICR2_SWY_LIM_CTRL); |
| pLineObj->icr2Values[VP880_ICR2_SWY_CTRL_INDEX+1] |= VP880_ICR2_SWY_LIM_CTRL1; |
| #endif /* VP880_CURRENT_LIMIT */ |
| /* Force ICR4 update - make sure it is what we think it is.. */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR4_WRT, VP880_ICR4_LEN, |
| pLineObj->icr4Values); |
| } |
| #endif /* VP880_TRACKER_SUPPORT */ |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Line Init: ICR2 0x%02X 0x%02X 0x%02X 0x%02X Ch %d", |
| pLineObj->icr2Values[0], pLineObj->icr2Values[1], |
| pLineObj->icr2Values[2], pLineObj->icr2Values[3], channelId)); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR2_WRT, VP880_ICR2_LEN, pLineObj->icr2Values); |
| |
| if (pDcOrFxoProfile == VP_PTABLE_NULL) { |
| status = Vp880ConfigLine(pLineCtx, pAcProfile, dcDefaultProf, pRingProfile); |
| } else { |
| status = Vp880ConfigLine(pLineCtx, pAcProfile, pDcOrFxoProfile, pRingProfile); |
| } |
| |
| if (status != VP_STATUS_SUCCESS) { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return status; |
| } |
| |
| /* Set to Disconnect */ |
| /* |
| * Set to Disconnect. Set current state to Standby in order to force line |
| * state function to change to Disconnect. Otherwise, no changes are made |
| * since it thinks device is already set correctly. |
| */ |
| pLineObj->lineState.currentState = VP_LINE_STANDBY; |
| Vp880SetLineStateInt(pLineCtx, VP_LINE_DISCONNECT); |
| pLineObj->lineState.usrCurrent = VP_LINE_DISCONNECT; |
| #endif /* VP880_FXS_SUPPORT */ |
| } |
| |
| status = VpImplementDefaultSettings(VP_NULL, pLineCtx); |
| |
| #ifdef VP880_FXS_SUPPORT |
| Vp880SetRelayState(pLineCtx, VP_RELAY_NORMAL); |
| #endif /* VP880_FXS_SUPPORT */ |
| |
| /* Post the line init complete event if status is succesfull */ |
| if (status == VP_STATUS_SUCCESS) { |
| pLineObj->lineEvents.response |= VP_LINE_EVID_LINE_INIT_CMP; |
| pLineObj->status |= VP880_INIT_COMPLETE; |
| } |
| |
| #ifdef VP880_FXO_SUPPORT |
| if (pLineObj->status & VP880_IS_FXO) { |
| pLineObj->lineTimers.timers.fxoTimer.disconnectDebounce = VP_FXO_DISCONNECT_DEBOUNCE; |
| } |
| #endif /* VP880_FXO_SUPPORT */ |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| return status; |
| } /* Vp880InitLine */ |
| |
| /** |
| * Vp880ConfigLine |
| * This function reloads a line of a device with the specified parameters. |
| * |
| * Preconditions: |
| * The device associated with this line must be initialized. |
| * |
| * Postconditions: |
| * The line pointed to be the line context passed is initialized with the |
| * profile data specified. This function returns the success code if the device |
| * associated with this line is initialized. |
| */ |
| VpStatusType |
| Vp880ConfigLine( |
| VpLineCtxType *pLineCtx, |
| VpProfilePtrType pAcProfile, /**< Pointer to AC coefficient data or |
| * profile index to be applied to this line. |
| */ |
| |
| VpProfilePtrType pDcOrFxoProfile, /**< Pointer to DC Feed (FXS) or Cfg |
| * (FX0) profile or profile index to be |
| * applied to this line. |
| */ |
| |
| VpProfilePtrType pRingProfile) /**< Pointer to Ringing profile or profile |
| * index to apply to this line |
| */ |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| |
| uint8 ecVal = pLineObj->ecVal; |
| |
| #ifdef VP880_FXS_SUPPORT |
| uint8 channelId = pLineObj->channelId; |
| uint8 sysStateConfig[VP880_SS_CONFIG_LEN]; |
| uint8 ringTypeByte; |
| VpProfilePtrType pRingProf = VP_PTABLE_NULL; |
| #endif |
| |
| uint8 profileIndex; |
| |
| VpProfileDataType *pMpiData; |
| |
| VpProfilePtrType pAcProf = VP_PTABLE_NULL; |
| VpProfilePtrType pDcFxoCfgProf = VP_PTABLE_NULL; |
| |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| #ifdef CSLAC_GAIN_RELATIVE |
| uint8 gainCSD[VP880_GR_GAIN_LEN]; |
| #endif |
| |
| #ifdef VP880_FXO_SUPPORT |
| uint8 loopSuperParams; |
| |
| /* |
| * Default value used if non provided. Note Ringing Detect 17-33Hz at 1/2 |
| * period due to 2x pulse from ringing detect input. |
| */ |
| #ifndef VP880_CLARE_RINGING_DETECT |
| uint8 fxoLoopThreshLow[VP880_LOOP_SUP_LEN] = {0x1C, 0xE1, 0x79, 0xEB}; |
| uint8 fxoLoopThreshHigh[VP880_LOOP_SUP_LEN] = {0x19, 0xF4, 0x79, 0xEB}; |
| #endif |
| |
| uint8 fxoLoopThresh[VP880_LOOP_SUP_LEN] = {0x19, 0xF4, 0x38, 0x78}; |
| #endif |
| |
| /* Proceed if device state is either in progress or complete */ |
| if (pDevObj->state & (VP_DEV_INIT_CMP | VP_DEV_INIT_IN_PROGRESS)) { |
| } else { |
| return VP_STATUS_DEV_NOT_INITIALIZED; |
| } |
| |
| /* |
| * Do not proceed if the device calibration is in progress. This could |
| * damage the device. |
| */ |
| if (pDevObj->state & VP_DEV_IN_CAL) { |
| return VP_STATUS_DEV_NOT_INITIALIZED; |
| } |
| |
| /* Check the legality of the AC profile */ |
| if (!VpCSLACIsProfileValid(VP_PROFILE_AC, |
| VP_CSLAC_AC_PROF_TABLE_SIZE, pDevObj->profEntry.acProfEntry, |
| pDevObj->devProfileTable.pAcProfileTable, pAcProfile, &pAcProf)) { |
| |
| return VP_STATUS_ERR_PROFILE; |
| } |
| |
| if (pLineObj->status & VP880_IS_FXO) { |
| #ifdef VP880_FXO_SUPPORT |
| /* Check the legality of the FXO profile */ |
| if (!VpCSLACIsProfileValid(VP_PROFILE_FXO_CONFIG, |
| VP_CSLAC_FXO_CONFIG_PROF_TABLE_SIZE, |
| pDevObj->profEntry.fxoConfigProfEntry, |
| pDevObj->devProfileTable.pFxoConfigProfileTable, |
| pDcOrFxoProfile, &pDcFxoCfgProf)) { |
| |
| return VP_STATUS_ERR_PROFILE; |
| } |
| #endif |
| } else { |
| #ifdef VP880_FXS_SUPPORT |
| /* Check the legality of the DC profile */ |
| if (!VpCSLACIsProfileValid(VP_PROFILE_DC, VP_CSLAC_DC_PROF_TABLE_SIZE, |
| pDevObj->profEntry.dcProfEntry, |
| pDevObj->devProfileTable.pDcProfileTable, |
| pDcOrFxoProfile, &pDcFxoCfgProf)) { |
| |
| return VP_STATUS_ERR_PROFILE; |
| } |
| #endif |
| } |
| |
| #ifdef VP880_FXS_SUPPORT |
| /* Check the legality of the Ringing profile */ |
| if (!VpCSLACIsProfileValid(VP_PROFILE_RING, VP_CSLAC_RINGING_PROF_TABLE_SIZE, |
| pDevObj->profEntry.ringingProfEntry, |
| pDevObj->devProfileTable.pRingingProfileTable, pRingProfile, |
| &pRingProf)) { |
| |
| return VP_STATUS_ERR_PROFILE; |
| } |
| #endif |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| /* |
| * Do not modify the line if line is in calibration. This could cause line |
| * calibration failure. Write to the update values that will be applied |
| * when calibration is complete (for provided profiles). |
| */ |
| if (pLineObj->status & VP880_LINE_IN_CAL) { |
| uint8 profileSize = 0; |
| if (pAcProf != VP_PTABLE_NULL) { |
| /* Error if the provided profile is larger than what we can copy */ |
| profileSize = pAcProf[VP_PROFILE_LENGTH] + VP_PROFILE_LENGTH + 1; |
| if (profileSize > VP880_AC_PROFILE_SIZE) { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_DEVICE_BUSY; |
| } |
| /* Size is ok. Copy profile and set update required flag */ |
| pLineObj->calLineData.updateFlags |= AC_PROFILE_UPDATE_REQ; |
| VpMemCpy(pLineObj->calLineData.acProfile, pAcProf, profileSize); |
| } |
| if (pDcFxoCfgProf != VP_PTABLE_NULL) { |
| /* Error if the provided profile is larger than what we can copy */ |
| profileSize = pDcFxoCfgProf[VP_PROFILE_LENGTH] + VP_PROFILE_LENGTH + 1; |
| if (profileSize > VP880_DC_PROFILE_SIZE) { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_DEVICE_BUSY; |
| } |
| /* Size is ok. Copy profile and set update required flag */ |
| pLineObj->calLineData.updateFlags |= DC_PROFILE_UPDATE_REQ; |
| VpMemCpy(pLineObj->calLineData.dcProfile, pDcFxoCfgProf, profileSize); |
| } |
| #ifdef VP880_FXS_SUPPORT |
| if (pRingProf != VP_PTABLE_NULL) { |
| /* Error if the provided profile is larger than what we can copy */ |
| profileSize = pRingProf[VP_PROFILE_LENGTH] + VP_PROFILE_LENGTH + 1; |
| if (profileSize > VP880_RINGING_PROFILE_SIZE) { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_DEVICE_BUSY; |
| } |
| /* Size is ok. Copy profile and set update required flag */ |
| pLineObj->calLineData.updateFlags |= RINGING_PROFILE_UPDATE_REQ; |
| VpMemCpy(pLineObj->calLineData.ringingProfile, pRingProf, profileSize); |
| } |
| #endif |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /* Load AC Coefficients */ |
| if (pAcProf != VP_PTABLE_NULL) { |
| profileIndex = VP_PROFILE_MPI_LEN + 1; |
| pMpiData = (VpProfileDataType *)(&pAcProfile[profileIndex]); |
| VpMpiCmdWrapper(deviceId, ecVal, NOOP_CMD, |
| pAcProfile[VP_PROFILE_MPI_LEN], pMpiData); |
| |
| #ifdef CSLAC_GAIN_RELATIVE |
| /* Update cached transmit and receive gains for SetRelGain */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_GX_GAIN_RD, VP880_GX_GAIN_LEN, gainCSD); |
| pLineObj->gain.gxInt = 0x4000 + VpConvertCsd2Fixed(gainCSD); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_GR_GAIN_RD, VP880_GR_GAIN_LEN, gainCSD); |
| pLineObj->gain.grInt = VpConvertCsd2Fixed(gainCSD); |
| #endif |
| |
| #ifdef CSLAC_GAIN_ABS |
| pLineObj->gain.absGxGain = VP_ABS_GAIN_UNKNOWN; |
| pLineObj->gain.absGrGain = VP_ABS_GAIN_UNKNOWN; |
| #endif |
| } |
| |
| if (pLineObj->status & VP880_IS_FXO) { |
| #ifdef VP880_FXO_SUPPORT |
| /* Configure an FXO line type */ |
| if (pDcFxoCfgProf != VP_PTABLE_NULL) { |
| #ifdef VP880_CLARE_RINGING_DETECT |
| uint8 tempRegValue; |
| #endif /* VP880_CLARE_RINGING_DETECT */ |
| /* |
| * LIU Threshold may have been provided in Volts or by Register Value. Convert to |
| * register value only. |
| */ |
| uint8 liuVoltage = pDcFxoCfgProf[VP_FXO_DIALING_PROFILE_LIU_THRESHOLD_MIN]; |
| if (liuVoltage > 15) { /* Only 3-bits in the device, so if larger than 15 it's volts */ |
| /* Round out to nearest programmable device setting */ |
| uint8 tempLiuVolt = (liuVoltage - 16); |
| |
| /* Steps are in 11V increments, so find the remainder */ |
| uint8 liuError = (tempLiuVolt % 11); |
| if (liuError > 5) { |
| tempLiuVolt += (11 - liuError); |
| } else { |
| tempLiuVolt -= liuError; |
| } |
| /* Update liuVoltage to match Device values */ |
| liuVoltage = (tempLiuVolt / 11); |
| } |
| |
| #ifndef VP880_CLARE_RINGING_DETECT |
| /* |
| * Force device Ringing Detector unless the minimum frequency is |
| * lower than device can support. |
| */ |
| if (pDcFxoCfgProf[VP_FXO_DIALING_PROFILE_RING_PERIOD_MAX_ACT] |
| >= VP880_MAX_RING_DET_PERIOD) { |
| /* Cache the "Low Freq" loop supervision register content */ |
| VpMemCpy(fxoLoopThresh, fxoLoopThreshLow, VP880_LOOP_SUP_LEN); |
| } else { |
| /* Cache the "High Freq" loop supervision register content */ |
| VpMemCpy(fxoLoopThresh, fxoLoopThreshHigh, VP880_LOOP_SUP_LEN); |
| } |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_DISC_VOLTAGE_MIN; |
| loopSuperParams = (pDcFxoCfgProf[profileIndex] << 3); |
| loopSuperParams &= 0x38; |
| fxoLoopThresh[0] &= ~(0x38); |
| fxoLoopThresh[0] |= loopSuperParams; |
| |
| /* |
| * Use the profile parameters for Ringing Detect minimum ONLY if |
| * the minimum ringing detect frequency is within range of device. |
| * Otherwise, force LIU/Ring Detect to 60V. |
| */ |
| if (pDcFxoCfgProf[VP_FXO_DIALING_PROFILE_RING_PERIOD_MAX_ACT] |
| < VP880_MAX_RING_DET_PERIOD) { |
| fxoLoopThresh[0] &= ~(VP880_LOOP_SUP_LIU_THRESH_BITS); |
| fxoLoopThresh[0] |= liuVoltage; |
| } |
| |
| fxoLoopThresh[VP880_RING_PERIOD_MIN_INDEX] = |
| pDcFxoCfgProf[VP_FXO_DIALING_PROFILE_RING_PERIOD_MIN]; |
| |
| /* |
| * Cache the Minimum Ringing Detect Period that is implemented in |
| * SW. |
| */ |
| pLineObj->ringDetMin = |
| pDcFxoCfgProf[VP_FXO_DIALING_PROFILE_RING_PERIOD_MIN]; |
| pLineObj->ringDetMin /= 4; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_RING_PERIOD_MAX_ACT; |
| pLineObj->ringDetMax = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_RING_PERIOD_MAX; |
| fxoLoopThresh[3] = pDcFxoCfgProf[profileIndex]; |
| #else /* VP880_CLARE_RINGING_DETECT */ |
| profileIndex = VP_FXO_DIALING_PROFILE_DISC_VOLTAGE_MIN; |
| loopSuperParams = (pDcFxoCfgProf[profileIndex] << 3); |
| loopSuperParams &= 0x38; |
| fxoLoopThresh[0] &= ~(0x38); |
| fxoLoopThresh[0] |= loopSuperParams; |
| fxoLoopThresh[0] |= VP880_RING_DETECT_PERIOD_ONLY; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_LIU_THRESHOLD_MIN; |
| fxoLoopThresh[0] &= ~(VP880_LOOP_SUP_LIU_THRESH_BITS); |
| fxoLoopThresh[0] |= liuVoltage; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_RING_PERIOD_MIN; |
| |
| #ifdef VP880_FXO_FULL_WAVE_RINGING |
| tempRegValue = pDcFxoCfgProf[profileIndex] / 2; |
| #else /* VP880_FXO_FULL_WAVE_RINGING */ |
| tempRegValue = pDcFxoCfgProf[profileIndex]; |
| #endif /* VP880_FXO_FULL_WAVE_RINGING */ |
| |
| fxoLoopThresh[VP880_RING_PERIOD_MIN_INDEX] = tempRegValue; |
| |
| /* |
| * Cache the Minimum Ringing Detect Period that is implemented in |
| * SW. |
| */ |
| pLineObj->ringDetMin = pDcFxoCfgProf[profileIndex]; |
| pLineObj->ringDetMin /= 4; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_RING_PERIOD_MAX_ACT; |
| pLineObj->ringDetMax = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_RING_PERIOD_MAX; |
| |
| #ifdef VP880_FXO_FULL_WAVE_RINGING |
| tempRegValue = pDcFxoCfgProf[profileIndex] / 2; |
| #else /* VP880_FXO_FULL_WAVE_RINGING */ |
| tempRegValue = pDcFxoCfgProf[profileIndex]; |
| #endif /* VP880_FXO_FULL_WAVE_RINGING */ |
| |
| fxoLoopThresh[3] = tempRegValue; |
| #endif /* VP880_CLARE_RINGING_DETECT */ |
| |
| if (pLineObj->ringDetMax == 0) { |
| pLineObj->ringDetMax = fxoLoopThresh[3] / 4; |
| } |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_ON_MSB; |
| pLineObj->digitGenStruct.dtmfOnTime = (pDcFxoCfgProf[profileIndex] << 8)&0xFF00; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_ON_LSB; |
| pLineObj->digitGenStruct.dtmfOnTime |= pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_OFF_MSB; |
| pLineObj->digitGenStruct.dtmfOffTime = (pDcFxoCfgProf[profileIndex] << 8)&0xFF00; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_OFF_LSB; |
| pLineObj->digitGenStruct.dtmfOffTime |= pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_PULSE_BREAK; |
| pLineObj->digitGenStruct.breakTime = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_PULSE_MAKE; |
| pLineObj->digitGenStruct.makeTime = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_FLASH_HOOK_MSB; |
| pLineObj->digitGenStruct.flashTime = (pDcFxoCfgProf[profileIndex] << 8)&0xFF00; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_FLASH_HOOK_LSB; |
| pLineObj->digitGenStruct.flashTime |= pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_INTERDIGIT_MSB; |
| pLineObj->digitGenStruct.dpInterDigitTime = (pDcFxoCfgProf[profileIndex] << 8)&0xFF00; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_INTERDIGIT_LSB; |
| pLineObj->digitGenStruct.dpInterDigitTime = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_PROFILE_VERSION; |
| if (pDcFxoCfgProf[profileIndex] >= VP_CSLAC_FXO_VERSION_DTMF_LEVEL) { |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_HIGH_LVL_MSB; |
| pLineObj->digitGenStruct.dtmfHighFreqLevel[0] = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_HIGH_LVL_LSB; |
| pLineObj->digitGenStruct.dtmfHighFreqLevel[1] = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_LOW_LVL_MSB; |
| pLineObj->digitGenStruct.dtmfLowFreqLevel[0] = pDcFxoCfgProf[profileIndex]; |
| |
| profileIndex = VP_FXO_DIALING_PROFILE_DTMF_LOW_LVL_LSB; |
| pLineObj->digitGenStruct.dtmfLowFreqLevel[1] = pDcFxoCfgProf[profileIndex]; |
| } else { |
| pLineObj->digitGenStruct.dtmfHighFreqLevel[0] = 0x1C; |
| pLineObj->digitGenStruct.dtmfHighFreqLevel[1] = 0x32; |
| pLineObj->digitGenStruct.dtmfLowFreqLevel[0] = 0x1C; |
| pLineObj->digitGenStruct.dtmfLowFreqLevel[1] = 0x32; |
| } |
| #endif /* VP_CSLAC_SEQ_EN */ |
| |
| fxoLoopThresh[VP880_LIU_DBNC_INDEX] &= ~VP880_LIU_DBNC_MASK; |
| fxoLoopThresh[VP880_LIU_DBNC_INDEX] |= |
| ((fxoLoopThresh[VP880_RING_PERIOD_MIN_INDEX] >> 3) & VP880_LIU_DBNC_MASK); |
| |
| if (!(fxoLoopThresh[VP880_RING_PERIOD_MIN_INDEX] & VP880_RING_PERIOD_1MS)) { |
| if ((fxoLoopThresh[VP880_LIU_DBNC_INDEX] & VP880_LIU_DBNC_MASK) > 0) { |
| fxoLoopThresh[VP880_LIU_DBNC_INDEX]--; |
| } |
| } |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_LOOP_SUP_WRT, VP880_LOOP_SUP_LEN, fxoLoopThresh); |
| |
| /* Cache the loop supervision register content */ |
| VpMemCpy(pLineObj->loopSup, fxoLoopThresh, VP880_LOOP_SUP_LEN); |
| } |
| |
| /* Cache this so we don't have to read it all the time */ |
| VpMemCpy(fxoLoopThresh, pLineObj->loopSup, VP880_LOOP_SUP_LEN); |
| pLineObj->lineTimers.timers.fxoTimer.maxPeriod = fxoLoopThresh[3]; |
| #endif /* VP880_FXO_SUPPORT */ |
| } else { |
| #ifdef VP880_FXS_SUPPORT |
| |
| /* Configure an FXS line type */ |
| |
| /* Ringing changed if profile passed */ |
| if (pRingProf != VP_PTABLE_NULL) { |
| uint8 tempRingPr[255]; |
| int16 biasErr; |
| |
| /* |
| * Clear flags to indicate generators are not programmed to user |
| * specified Ringing values. |
| */ |
| pLineObj->status &= ~(VP880_RING_GEN_NORM | VP880_RING_GEN_REV); |
| |
| /* |
| * Ringing Profile May affect the system state register, so read |
| * what it is before the profile, and set it back to all values |
| * except what can change in the profile |
| */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_SS_CONFIG_RD, |
| VP880_SS_CONFIG_LEN, sysStateConfig); |
| |
| profileIndex = VP_PROFILE_MPI_LEN + 1; |
| pMpiData = (VpProfileDataType *)&pRingProf[profileIndex]; |
| |
| VpMemCpy(tempRingPr, pMpiData, pRingProf[VP_PROFILE_MPI_LEN]); |
| |
| biasErr = (int16)((((uint16)(tempRingPr[2]) << 8) & 0xFF00) + |
| ((uint16)(tempRingPr[3]) & 0x00FF)); |
| |
| /* Apply the offset calibration to the BIAS */ |
| if ((pLineObj->slicValueCache & VP880_SS_POLARITY_MASK) == 0x00) { |
| /* Normal polarity */ |
| biasErr -= ((pDevObj->vp880SysCalData.sigGenAError[channelId][0] - |
| pDevObj->vp880SysCalData.vocOffset[channelId][VP880_NORM_POLARITY]) * 16 / 10); |
| } else { |
| /* Reverse polarity */ |
| biasErr += ((pDevObj->vp880SysCalData.sigGenAError[channelId][0] - |
| pDevObj->vp880SysCalData.vocOffset[channelId][VP880_REV_POLARITY]) * 16 / 10); |
| } |
| tempRingPr[2] = (uint8)((biasErr >> 8) & 0x00FF); |
| tempRingPr[3] = (uint8)(biasErr & 0x00FF); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, NOOP_CMD, pRingProf[VP_PROFILE_MPI_LEN], tempRingPr); |
| |
| VpMemCpy(pLineObj->ringingParams, &pRingProf[profileIndex + 1], |
| VP880_RINGER_PARAMS_LEN); |
| |
| ringTypeByte = pRingProf[VP_PROFILE_MPI_LEN + |
| pRingProf[VP_PROFILE_MPI_LEN] + VP_PROFILE_RING_TYPE_OFFSET]; |
| |
| pLineObj->status &= ~(VP880_UNBAL_RINGING); |
| pLineObj->status |= (ringTypeByte ? VP880_UNBAL_RINGING : 0x0000); |
| |
| /* |
| * Nothing in this register should be allowed to change, but the |
| * Ringing profile may have changed this value to be compatible |
| * with other device profiles. So correct it. |
| */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_SS_CONFIG_WRT, |
| VP880_SS_CONFIG_LEN, sysStateConfig); |
| } |
| |
| /* Set Loop Supervision and DC Feed */ |
| if (pDcFxoCfgProf != VP_PTABLE_NULL) { |
| profileIndex = VP_PROFILE_MPI_LEN + 1; |
| pMpiData = (VpProfileDataType *)&pDcFxoCfgProf[profileIndex]; |
| |
| if (pDevObj->stateInt & VP880_IS_ABS) { /* ABS Workaround */ |
| #ifdef VP880_ABS_SUPPORT |
| /* If the VOC set >= theshold, disable longitudinal clamps */ |
| if ((pDcFxoCfgProf[VP880_VOC_PROFILE_POSITION] & VP880_VOC_MASK) |
| >= VP880_VOC_51V) { |
| pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX] &= ~VP880_ICR3_SAT_LIM_25_CTRL; |
| pLineObj->icr3Values[VP880_ICR3_LONG_UNCLAMP_INDEX] |= VP880_ICR3_LONG_UNCLAMP; |
| pLineObj->icr3Values[VP880_ICR3_LONG_UNCLAMP_INDEX+1] |= VP880_ICR3_LONG_UNCLAMP; |
| } else { |
| pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX] |
| |= VP880_ICR3_SAT_LIM_25_CTRL; |
| pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX+1] |
| &= ~VP880_ICR3_SAT_LIM_25_CTRL; |
| pLineObj->icr3Values[VP880_ICR3_LONG_UNCLAMP_INDEX] |
| &= ~VP880_ICR3_LONG_UNCLAMP; |
| } |
| #endif /* VP880_ABS_SUPPORT */ |
| } else { /* Tracker Workaround */ |
| #ifdef VP880_TRACKER_SUPPORT |
| /* If the VOC set > 48V, disable longitudinal clamps */ |
| if ((pDcFxoCfgProf[VP880_VOC_PROFILE_POSITION] & VP880_VOC_MASK) > VP880_VOC_48V) { |
| /* Disable longitudinal clamps */ |
| pLineObj->icr3Values[VP880_ICR3_LONG_UNCLAMP_INDEX] |= VP880_ICR3_LONG_UNCLAMP; |
| pLineObj->icr3Values[VP880_ICR3_LONG_UNCLAMP_INDEX+1] |= VP880_ICR3_LONG_UNCLAMP; |
| |
| /* Remove Workaround from other conditions */ |
| pLineObj->icr3Values[VP880_ICR3_LONG_FIXED_INDEX] &= ~VP880_ICR3_LONG_FIXED; |
| } else { |
| /* If the VOC <= 48V, enable longitudinal clamps */ |
| pLineObj->icr3Values[VP880_ICR3_LONG_FIXED_INDEX] |= VP880_ICR3_LONG_FIXED; |
| pLineObj->icr3Values[VP880_ICR3_LONG_FIXED_INDEX+1] &= ~VP880_ICR3_LONG_FIXED; |
| |
| /* Remove Workaround from other conditions */ |
| pLineObj->icr3Values[VP880_ICR3_LONG_UNCLAMP_INDEX] &= ~VP880_ICR3_LONG_UNCLAMP; |
| } |
| #endif /* VP880_TRACKER_SUPPORT */ |
| } |
| |
| if (pDcFxoCfgProf[VP_PROFILE_VERSION] >= 1) { |
| /* This profile contains a hook hysteresis value */ |
| pLineObj->hookHysteresis = pDcFxoCfgProf[VP880_HOOK_HYST_POSITION]; |
| } else { |
| pLineObj->hookHysteresis = 0; |
| } |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Config Line: Channel %d: Writing ICR2 0x%02X 0x%02X 0x%02X 0x%02X", |
| channelId, pLineObj->icr2Values[0], pLineObj->icr2Values[1], |
| pLineObj->icr2Values[2], pLineObj->icr2Values[3])); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR2_WRT, VP880_ICR2_LEN, pLineObj->icr2Values); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("ICR3 Workaround: 0x%02X 0x%02X 0x%02X 0x%02X Ch %d", |
| pLineObj->icr3Values[0], pLineObj->icr3Values[1], |
| pLineObj->icr3Values[2], pLineObj->icr3Values[3], channelId)); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR3_WRT, VP880_ICR3_LEN, pLineObj->icr3Values); |
| |
| /* Cache the loop supervision register content */ |
| VpMemCpy(pLineObj->loopSup, &pMpiData[1], VP880_LOOP_SUP_LEN); |
| |
| /* If off-hook -> apply the hysteresis */ |
| if ((VpCslacLineCondType)(pLineObj->lineState.condition & VP_CSLAC_HOOK) |
| == VP_CSLAC_HOOK) { |
| if ((pMpiData[1] & VP880_LOOP_SUP_LIU_THRESH_BITS) >= pLineObj->hookHysteresis) { |
| pMpiData[1] -= pLineObj->hookHysteresis; |
| } else { |
| pMpiData[1] &= ~VP880_LOOP_SUP_LIU_THRESH_BITS; |
| } |
| } |
| |
| /* Write the Profile Data */ |
| VpMpiCmdWrapper(deviceId, ecVal, NOOP_CMD, pDcFxoCfgProf[VP_PROFILE_MPI_LEN], pMpiData); |
| |
| if (pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION] >= VP880_REV_JE) { |
| uint8 icr5Values[VP880_ICR5_LEN]; |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR5_RD, VP880_ICR5_LEN, icr5Values); |
| |
| icr5Values[VP880_ICR5_FEED_HOLD_INDEX] &= ~VP880_ICR5_FEED_HOLD_MASK; |
| |
| /* Device value is x + 18mA, so threshold is > 35mA */ |
| if ((pDcFxoCfgProf[VP880_ILA_PROFILE_POSITION] & VP880_ILA_MASK) > 17) { |
| icr5Values[VP880_ICR5_FEED_HOLD_INDEX] |= 0xF0; |
| } else { |
| icr5Values[VP880_ICR5_FEED_HOLD_INDEX] |= 0xA0; |
| } |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR5_WRT, VP880_ICR5_LEN, icr5Values); |
| } |
| |
| /* Copy Feed for Calibration reference */ |
| VP_CALIBRATION(VpLineCtxType, pLineCtx, ("Copying DC Feed Reference in VpConfigLine()")); |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_DC_FEED_RD, |
| VP880_DC_FEED_LEN, pLineObj->calLineData.dcFeedRef); |
| |
| /* Update the line and device objects (dc feed register) for calibrated values. */ |
| Vp880UpdateCalValue(pLineCtx); |
| } |
| #endif /* VP880_FXS_SUPPORT */ |
| } |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_SUCCESS; |
| } /* Vp880ConfigLine() */ |
| |
| /* |
| * Vp880UpdateCalValue() |
| * This function loads the device with calibration values provided by VpCal() |
| * "Apply System Coefficient" process. |
| * |
| * Preconditions: |
| * System calibration values provided or calibration previously run. |
| * |
| * Postconditions: |
| * The device is loaded per the applied calibration values. |
| */ |
| bool |
| Vp880UpdateCalValue( |
| VpLineCtxType *pLineCtx) |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| |
| uint8 ecVal = pLineObj->ecVal; |
| |
| bool calStatus = FALSE; |
| |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880UpdateCalValue+")); |
| |
| if ((pLineObj->calLineData.dcFeedRef[0] == 0x00) || (pLineObj->status & VP880_IS_FXO)) { |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880UpdateCalValue-")); |
| return calStatus; |
| } |
| |
| /* |
| * Update the target DC Feed registers used after calibration has |
| * been run. So we don't need to replace VAS (0 only if calibration |
| * not run, but then corrected during calibration). |
| */ |
| pLineObj->calLineData.dcFeed[0] &= ~VP880_VOC_VALUE_MASK; |
| pLineObj->calLineData.dcFeed[0] |= (pLineObj->calLineData.dcFeedRef[0] & VP880_VOC_VALUE_MASK); |
| |
| pLineObj->calLineData.dcFeedPr[0] &= ~VP880_VOC_VALUE_MASK; |
| pLineObj->calLineData.dcFeedPr[0] |= (pLineObj->calLineData.dcFeedRef[0] & VP880_VOC_VALUE_MASK); |
| |
| pLineObj->calLineData.dcFeedPr[1] &= ~VP880_ILA_MASK; |
| pLineObj->calLineData.dcFeedPr[1] |= (pLineObj->calLineData.dcFeedRef[1] & VP880_ILA_MASK); |
| |
| pLineObj->calLineData.dcFeed[1] &= ~VP880_ILA_MASK; |
| pLineObj->calLineData.dcFeed[1] |= (pLineObj->calLineData.dcFeedRef[1] & VP880_ILA_MASK); |
| |
| /* |
| * Adjust for the errors if previously calibrated. The ILA function |
| * returns "TRUE" if an adjustment was made meaning calibration |
| * done previously, FALSE if not. |
| */ |
| if (Vp880AdjustIla(pLineCtx, (pLineObj->calLineData.dcFeedRef[1] & VP880_ILA_MASK)) == TRUE) { |
| calStatus = TRUE; |
| Vp880AdjustVoc(pLineCtx, ((pLineObj->calLineData.dcFeedRef[0] >> 2) & 0x7), TRUE); |
| |
| if (!(pDevObj->stateInt & VP880_IS_ABS)) { /* Tracker only */ |
| #ifdef VP880_TRACKER_SUPPORT |
| uint16 vasVoltScale; |
| uint8 channelId = pLineObj->channelId; |
| |
| /* Set VAS to device calibrated values */ |
| vasVoltScale = (VP880_VAS_START + (uint16)pDevObj->vp880SysCalData.vas[channelId][VP880_NORM_POLARITY] * VP880_VAS_STEP); |
| VpCSLACSetVas(pLineObj->calLineData.dcFeed, vasVoltScale); |
| |
| vasVoltScale = (VP880_VAS_START + (uint16)pDevObj->vp880SysCalData.vas[channelId][VP880_REV_POLARITY] * VP880_VAS_STEP); |
| VpCSLACSetVas(pLineObj->calLineData.dcFeedPr, vasVoltScale); |
| |
| /* |
| * BatteryCalAdjust() takes care of the device object wideband 'OR' |
| * operation to the provided ec value as needed. |
| */ |
| Vp880BatteryCalAdjust(pDevObj, VP880_EC_CH1); |
| Vp880BatteryCalAdjust(pDevObj, VP880_EC_CH2); |
| #endif /* VP880_TRACKER_SUPPORT */ |
| } else { |
| #ifdef VP880_ABS_SUPPORT |
| VpLineStateType lineState; |
| int16 targetVoltY, targetVoltZ; |
| |
| VpGetLineState(pLineCtx, &lineState); |
| Vp880GetLineStateABS(pLineCtx, lineState, FALSE); |
| |
| /* Compute Errors and make corrections */ |
| targetVoltY = (pDevObj->swParams[VP880_SWY_LOCATION] & VP880_VOLTAGE_MASK); |
| targetVoltZ = (pDevObj->swParams[VP880_SWZ_LOCATION] & VP880_VOLTAGE_MASK); |
| |
| VP_CALIBRATION(VpLineCtxType, pLineCtx, ("ABS: Channel %d in State %d TargetY %d TargetZ %d", |
| pLineObj->channelId, lineState, targetVoltY, targetVoltZ)); |
| |
| Vp880AbvMakeAdjustment(pDevObj, &targetVoltY, &targetVoltZ); |
| #endif /* VP880_ABS_SUPPORT */ |
| } |
| |
| if (pLineObj->slicValueCache & VP880_SS_POLARITY_MASK) { |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_DC_FEED_WRT, |
| VP880_DC_FEED_LEN, pLineObj->calLineData.dcFeedPr); |
| } else { |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_DC_FEED_WRT, |
| VP880_DC_FEED_LEN, pLineObj->calLineData.dcFeed); |
| } |
| } |
| VP_CALIBRATION(VpLineCtxType, pLineCtx, |
| ("Vp880UpdateCalValue() Chan %d: DC Feed Values Normal 0x%02X 0x%02X", |
| pLineObj->channelId, |
| pLineObj->calLineData.dcFeed[0], pLineObj->calLineData.dcFeed[1])); |
| |
| VP_CALIBRATION(VpLineCtxType, pLineCtx, |
| ("Vp880UpdateCalValue() Chan %d: DC Feed Values Reverse 0x%02X 0x%02X", |
| pLineObj->channelId, |
| pLineObj->calLineData.dcFeedPr[0], pLineObj->calLineData.dcFeedPr[1])); |
| |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880UpdateCalValue-")); |
| return calStatus; |
| } /* Vp880UpdateCalValue() */ |
| |
| /** |
| * Vp880InitProfile() |
| * This function is used to initialize profile tables in Vp880. |
| * |
| * Preconditions: |
| * The device associated with this line must be initialized. |
| * |
| * Postconditions: |
| * Stores the given profile at the specified index of the profile table. |
| */ |
| VpStatusType |
| Vp880InitProfile( |
| VpDevCtxType *pDevCtx, |
| VpProfileType type, |
| VpProfilePtrType pProfileIndex, |
| VpProfilePtrType pProfile) |
| { |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| VpStatusType status = VP_STATUS_SUCCESS; |
| |
| uint8 profIndex8; /* Used for 8-bit profile table masking */ |
| uint16 profIndex16; /* Used for 16-bit profile table masking */ |
| |
| /* |
| * If the profile data is an index, indicated by Get Profile Index return |
| * value of > -1, return an error (cannot init an indexed entry with an |
| * index). |
| */ |
| int profileIndex = VpGetProfileIndex(pProfile); |
| |
| if (profileIndex >= 0) { |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| /* |
| * If pProfileIndex is -1, the profile is of pointer type and invalid, |
| * otherwise it is an index. If it's an index, make sure the range is |
| * valid. |
| */ |
| profileIndex = VpGetProfileIndex(pProfileIndex); |
| if (profileIndex < 0) { |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| profIndex8 = (uint8)profileIndex; |
| profIndex16 = (uint16)profileIndex; |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| /* |
| * The correct types are passed, but check to make sure the specific profile type being |
| * initialized is valid as well as the index value |
| */ |
| switch(type) { |
| case VP_PROFILE_DEVICE: |
| if (profIndex8 >= VP_CSLAC_DEV_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_DEVICE, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pDevProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.devProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.devProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_AC: |
| if (profIndex8 >= VP_CSLAC_AC_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_AC, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pAcProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.acProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.acProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_DC: |
| if (profIndex8 >= VP_CSLAC_DC_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_DC, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pDcProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.dcProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.dcProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_RING: |
| if (profIndex8 >= VP_CSLAC_RINGING_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_RING, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pRingingProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.ringingProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.ringingProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_RINGCAD: |
| if (profIndex8 >= VP_CSLAC_RING_CADENCE_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_RINGCAD, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pRingingCadProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.ringCadProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.ringCadProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_TONE: |
| if (profIndex16 >= VP_CSLAC_TONE_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_TONE, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pToneProfileTable[profIndex16] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.toneProfEntry &= ~(0x01 << profIndex16); |
| } else { |
| pDevObj->profEntry.toneProfEntry |= (0x01 << profIndex16); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_TONECAD: |
| if (profIndex16 >= VP_CSLAC_TONE_CADENCE_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_TONECAD, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pToneCadProfileTable[profIndex16] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.toneCadProfEntry &= ~(0x01 << profIndex16); |
| } else { |
| pDevObj->profEntry.toneCadProfEntry |= (0x01 << profIndex16); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_METER: |
| if (profIndex8 >= VP_CSLAC_METERING_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_METER, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pMeteringProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.meterProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.meterProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_CID: |
| if (profIndex8 >= VP_CSLAC_CALLERID_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_CID, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pCallerIdProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.cidCadProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.cidCadProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| case VP_PROFILE_FXO_CONFIG: |
| if (profIndex8 >= VP_CSLAC_FXO_CONFIG_PROF_TABLE_SIZE) { |
| status = VP_STATUS_INVALID_ARG; |
| } else { |
| if(VpVerifyProfileType(VP_PROFILE_FXO_CONFIG, pProfile) == TRUE) { |
| pDevObj->devProfileTable.pFxoConfigProfileTable[profIndex8] = pProfile; |
| /* |
| * If the profile is null, then clear the flag in the profile entry table to |
| * indicate that this profile is no longer valid. |
| */ |
| if (pProfile == VP_PTABLE_NULL) { |
| pDevObj->profEntry.fxoConfigProfEntry &= ~(0x01 << profIndex8); |
| } else { |
| pDevObj->profEntry.fxoConfigProfEntry |= (0x01 << profIndex8); |
| } |
| } else { |
| status = VP_STATUS_ERR_PROFILE; |
| } |
| } |
| break; |
| |
| default: |
| status = VP_STATUS_INVALID_ARG; |
| break; |
| } |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| return status; |
| } /* Vp880InitProfile() */ |
| |
| #ifdef VP880_FXS_SUPPORT |
| /** |
| * Vp880FreeRun() |
| * This function is called by the application when it wants to prepare the |
| * system for a restart, or by the VP-API-II internally when a clock fault or |
| * other "sign" of a restart is detected. |
| * |
| * Preconditions: |
| * Conditions defined by purpose of Api Tick. |
| * |
| * Postconditions: |
| * Device and line are in states 'ready" for a system reboot to occur. Lines |
| * are set to VP_LINE_STANDBY if previously ringing. |
| */ |
| VpStatusType |
| Vp880FreeRun( |
| VpDevCtxType *pDevCtx, |
| VpFreeRunModeType freeRunMode) |
| { |
| VpLineCtxType *pLineCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| Vp880LineObjectType *pLineObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| |
| uint8 maxChan = pDevObj->staticInfo.maxChannels; |
| |
| uint8 ecVal = pDevObj->ecVal; |
| VpLineStateType lineState; |
| uint8 powerMode[VP880_REGULATOR_CTRL_LEN]; |
| |
| uint8 channelId; |
| |
| VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880FreeRun Mode %d", freeRunMode)); |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| /* |
| * Time value is passed in 500us increment. If timeOut = 0, only PCLK |
| * recovery exits restart prepare operations. If less than one tick, force |
| * a one tick timeout. |
| */ |
| if (freeRunMode == VP_FREE_RUN_STOP) { |
| Vp880RestartComplete(pDevCtx); |
| /* |
| * Clear the device as being forced into free run mode by application. |
| * This allows PCLK fault detection to automatically enter/exit free |
| * run mode. |
| */ |
| pDevObj->stateInt &= ~VP880_FORCE_FREE_RUN; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /* Take the lines out of Ringing if necessary */ |
| for (channelId = 0; channelId < maxChan; channelId++) { |
| pLineCtx = pDevCtx->pLineCtx[channelId]; |
| if (pLineCtx != VP_NULL) { |
| pLineObj = pLineCtx->pLineObj; |
| |
| if (pLineObj->status & VP880_LINE_IN_CAL) { |
| lineState = pLineObj->calLineData.usrState; |
| } else { |
| lineState = pLineObj->lineState.usrCurrent; |
| } |
| if (lineState == VP_LINE_RINGING) { |
| Vp880SetLineState(pLineCtx, VP_LINE_STANDBY); |
| } |
| if (lineState == VP_LINE_RINGING_POLREV) { |
| Vp880SetLineState(pLineCtx, VP_LINE_STANDBY_POLREV); |
| } |
| } |
| } |
| |
| /* |
| * Load the free run timing, if available. Otherwise just force the switcher |
| * to HP mode and take control. |
| */ |
| if (pDevObj->intSwParamsFR[0] != 0x00) { |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_INT_SWREG_PARAM_WRT, |
| VP880_INT_SWREG_PARAM_LEN, pDevObj->intSwParamsFR); |
| } else { |
| /* Force control of the power mode */ |
| pDevObj->swParamsCache[VP880_SWY_AUTOPOWER_INDEX] |= VP880_SWY_AUTOPOWER_DIS; |
| pDevObj->swParamsCache[VP880_SWZ_AUTOPOWER_INDEX] |= VP880_SWZ_AUTOPOWER_DIS; |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_PARAM_WRT, |
| VP880_REGULATOR_PARAM_LEN, pDevObj->swParamsCache); |
| |
| /* Change the Switchers to High Power Mode */ |
| powerMode[0] = VP880_SWY_HP | VP880_SWZ_HP; |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_CTRL_WRT, |
| VP880_REGULATOR_CTRL_LEN, powerMode); |
| } |
| |
| /* |
| * Mark the device as being forced into free run mode by application. This |
| * prevents auto-recovery when PCLK is restored. |
| */ |
| pDevObj->stateInt |= VP880_FORCE_FREE_RUN; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_SUCCESS; |
| } /* Vp880FreeRun() */ |
| |
| /** |
| * Vp880RestartComplete() |
| * This function is called by the VP-API-II internally when a clock fault is |
| * removed. |
| * |
| * Preconditions: |
| * Conditions defined by purpose of Api Tick. |
| * |
| * Postconditions: |
| * Device and line are in states recovered from a reboot. |
| */ |
| void |
| Vp880RestartComplete( |
| VpDevCtxType *pDevCtx) |
| { |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| uint8 ecVal = pDevObj->ecVal; |
| uint8 powerMode[VP880_REGULATOR_CTRL_LEN]; |
| |
| /* |
| * Restore original timing if they were changed, otherwise change back the |
| * power mode and relinquish control. |
| */ |
| if (pDevObj->intSwParamsFR[0] != 0x00) { |
| /* Restore the original timings */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_INT_SWREG_PARAM_WRT, |
| VP880_INT_SWREG_PARAM_LEN, pDevObj->intSwParams); |
| } else { |
| /* Change the Switchers to the original Power Mode */ |
| if (pDevObj->stateInt & VP880_IS_ABS) { |
| #ifdef VP880_ABS_SUPPORT |
| uint8 systemConfig = (pDevObj->devProfileData.systemConfig & VP880_ABS_CFG_MASK); |
| |
| if (systemConfig == VP880_ABS_CFG_SLAVE) { |
| powerMode[0] = VP880_SWY_LP | VP880_SWY_LP; |
| } else if (systemConfig == VP880_ABS_CFG_SINGLE) { |
| powerMode[0] = VP880_SWY_MP | VP880_SWY_MP; |
| } else { /* systemConfig == VP880_ABS_CFG_MASTER */ |
| powerMode[0] = VP880_SWY_HP | VP880_SWY_HP; |
| } |
| #endif /* VP880_ABS_SUPPORT */ |
| } else { |
| #ifdef VP880_TRACKER_SUPPORT |
| powerMode[0] = VP880_SWY_LP | VP880_SWZ_LP; |
| #endif /* VP880_TRACKER_SUPPORT */ |
| } |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_CTRL_WRT, |
| VP880_REGULATOR_CTRL_LEN, powerMode); |
| |
| /* Relinquish control of the power mode */ |
| pDevObj->swParamsCache[VP880_SWY_AUTOPOWER_INDEX] &= ~VP880_SWY_AUTOPOWER_DIS; |
| pDevObj->swParamsCache[VP880_SWZ_AUTOPOWER_INDEX] &= ~VP880_SWZ_AUTOPOWER_DIS; |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_REGULATOR_PARAM_WRT, |
| VP880_REGULATOR_PARAM_LEN, pDevObj->swParamsCache); |
| } |
| } /* Vp880RestartComplete() */ |
| |
| /** |
| * Vp880CopyDefaultFRProfile() |
| * This function is used to copy the default Free Run switcher timing parameters |
| * to the device object used in Free Run mode. This is needed when values are |
| * not provided in the device profile. |
| * |
| * Preconditions: |
| * None. |
| * |
| * Postconditions: |
| * The device object is updated with the default free run switcher timing values. |
| */ |
| static void |
| Vp880CopyDefaultFRProfile( |
| Vp880DeviceObjectType *pDevObj) |
| { |
| if (pDevObj->stateInt & VP880_IS_ABS) { |
| #ifdef VP880_ABS_SUPPORT |
| /* ABS free run default profile */ |
| uint8 intSwParamsFR_ABS[VP880_INT_SWREG_PARAM_LEN] = { |
| 0x2C, 0x40, 0x2C, 0x40, 0x2C, 0x40 |
| }; |
| |
| VpMemCpy(pDevObj->intSwParamsFR, intSwParamsFR_ABS, VP880_INT_SWREG_PARAM_LEN); |
| #endif /* VP880_ABS_SUPPORT */ |
| } else { |
| #ifdef VP880_TRACKER_SUPPORT |
| /* |
| * The 1st timing value can't be 0x00, so it's a marker value -> no profile |
| * available |
| */ |
| uint8 intSwParamsFR_DFLT[VP880_INT_SWREG_PARAM_LEN] = { |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| VpMemCpy(pDevObj->intSwParamsFR, intSwParamsFR_DFLT, VP880_INT_SWREG_PARAM_LEN); |
| #endif /* VP880_TRACKER_SUPPORT */ |
| } |
| } /* Vp880CopyDefaultFRProfile() */ |
| #endif /* VP880_FXS_SUPPORT */ |
| #endif |
| |