blob: e5ab2eb0ff0ca175ce77a6cef8dcd89ba8c4d9e0 [file] [log] [blame]
/******************************************************************************
Copyright (c) 2014-2015 Lantiq Deutschland GmbH
Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
Copyright 2016, Intel Corporation.
For licensing information, see the file 'LICENSE' in the root folder of
this software module.
******************************************************************************/
/**
\file dxs_init.c
Implementation of initialization functions.
*/
/* ========================================================================== */
/* Includes */
/* ========================================================================== */
#include <stdlib.h>
#include "dxs_config.h"
#include "dxs_version.h"
#include "dxs_init.h"
#include "dxs_errno.h"
#include "dxs_error.h"
#include "dxs_fw_cmd.h"
#include "dxs_pcm.h"
#include "dxs_sdd.h"
#include "dxs_sig.h"
#include "dxs_gpio.h"
#include "dxs_access.h"
#include "dxs_cid.h"
#include "dxs_pollint.h"
#include "dxs_outbox.h"
#include "dxs_event.h"
#include "dxs_spi.h"
#include "dxs_dcdc_hw.h"
#include "dxs_ring.h"
#ifdef EVENT_LOGGER_DEBUG
#include <sys/ioctl.h>
#endif
const char DXS_WHATVERSION[] = DXS_WHAT_STR;
/* ========================================================================== */
/* Macro definitions */
/* ========================================================================== */
/* ========================================================================== */
/* Type definitions */
/* ========================================================================== */
/** Data structure for DXS_FW_SYS_VERS_ECMD firmware command */
typedef struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
CMD_HEAD_BE;
/** Device Number */
uint32_t DEVNR : 11;
/** Calender Week */
uint32_t CW : 6;
/** Production Year */
uint32_t YEAR : 6;
/** Channel */
uint32_t CH : 1;
/** Device ID Representing PEB Number */
uint32_t DEV : 8;
/** Major */
uint32_t MAJ : 8;
/** Minor */
uint32_t MIN : 8;
/** Hotfix */
uint32_t HF : 8 ;
/** Reserved */
uint32_t Res02 : 8;
/** Time Stamp */
uint32_t TIME;
#else
CMD_HEAD_LE;
/** Device ID Representing PEB Number */
uint32_t DEV : 8;
/** Channel */
uint32_t CH : 1;
/** Production Year */
uint32_t YEAR : 6;
/** Calender Week */
uint32_t CW : 6;
/** Device Number */
uint32_t DEVNR : 11;
/** Reserved */
uint32_t Res02 : 8;
/** Hotfix */
uint32_t HF : 8 ;
/** Minor */
uint32_t MIN : 8;
/** Major */
uint32_t MAJ : 8;
/** Time Stamp */
uint32_t TIME;
#endif
} __attribute__ ((packed)) DXS_FW_SYS_VERS_t;
#define DXS_FW_SYS_VERS_ECMD 6
#define DXS_FW_SYS_VERS_LENGTH 12
/** Data structure for system capabilities firmware command */
typedef struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
CMD_HEAD_BE;
/* Reserved */
uint32_t Res02 : 25;
/* Howler Support Available */
uint32_t HOWLER : 1;
/* Caller ID Available */
uint32_t CID : 1;
/* Universal Tone Detector Available */
uint32_t UTD : 1;
/* Teletax Support Available */
uint32_t TTX : 1;
/* Reserved */
uint32_t Res03 : 1;
/* AC Level Meter Support Available */
uint32_t ACLM : 1;
/* GR909 available */
uint32_t GR909 : 1;
#else
CMD_HEAD_LE;
/* GR909 available */
uint32_t GR909 : 1;
/* AC Level Meter Support Available */
uint32_t ACLM : 1;
/* Reserved */
uint32_t Res03 : 1;
/* Teletax Support Available */
uint32_t TTX : 1;
/* Universal Tone Detector Available */
uint32_t UTD : 1;
/* Caller ID Available */
uint32_t CID : 1;
/* Howler Support Available */
uint32_t HOWLER : 1;
/* Reserved */
uint32_t Res02 : 25;
#endif
} __attribute__ ((packed)) DXS_FW_SYS_CAPS_t;
#define DXS_FW_SYS_CAPS_ECMD 7
#define DXS_FW_SYS_CAPS_LENGTH 4
/** Data structure for DXS_FW_SYS_Control_ECMD firmware command */
typedef struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
CMD_HEAD_BE;
/* Reserved */
uint32_t Res02 : 25;
/* Sync-Fail/ Clock-Fail Handling Enable */
uint32_t SYCLKE : 1;
/* PLL Limiter Enable */
uint32_t PLIM : 1;
/* Charge Pump Voltage Level */
uint32_t CP_VOLT : 3;
/* Charge Pump Enable */
uint32_t CP_EN : 1;
/* Sleep Enable */
uint32_t SE : 1;
#else
CMD_HEAD_LE;
/* Sleep Enable */
uint32_t SE : 1;
/* Charge Pump Enable */
uint32_t CP_EN : 1;
/* Charge Pump Voltage Level */
uint32_t CP_VOLT : 3;
/* PLL Limiter Enable */
uint32_t PLIM : 1;
/* Sync-Fail/ Clock-Fail Handling Enable */
uint32_t SYCLKE : 1;
/* Reserved */
uint32_t Res02 : 25;
#endif
} __attribute__ ((packed)) DXS_FW_SYS_Control_t;
#define DXS_FW_SYS_Control_ECMD 8
#define DXS_FW_SYS_Control_LENGTH 4
#define DXS_FW_SYS_Control_CP_VOLT_5_0V 3
/** Device capabilities */
typedef struct
{
/* status flag */
uint32_t flag;
#define DXS_DEV_CAPS_INITIALIZED 1
#define DXS_DEV_CAPS_UPDATED 2
#define DXS_DEV_SYS_CTRL_UPDATED 4
/* device version */
DXS_Dev_t dev;
/* device package */
DXS_Package_t pack;
/* firmware version */
DXS_FW_SYS_VERS_t fw_vers;
/* firmware capabilities */
DXS_FW_SYS_CAPS_t fw_caps;
/* firmware system control */
DXS_FW_SYS_Control_t fw_sys_ctrl;
} DXS_Dev_Caps_t;
/* ========================================================================== */
/* Global variables */
/* ========================================================================== */
/* static data */
static DXS_DEVICE_t dxs_devices[DXS_MAX_DEVICES] = {0};
static DXS_Dev_Caps_t dxs_caps[DXS_MAX_DEVICES] = {0};
/* ========================================================================== */
/* Function prototypes */
/* ========================================================================== */
static int32_t dxs_controller_reset(DXS_DEVICE_t *pDev);
/* ========================================================================== */
/* Function implementation */
/* ========================================================================== */
#ifdef EVENT_LOGGER_DEBUG
static void dxs_el_register(DXS_DEVICE_t *pDev)
{
EL_IoctlRegister_t el_reg;
int ret;
pDev->el_fd = open(EL_DEVICE_NAME, 2, 0644);
if (pDev->el_fd < 0)
{
return;
}
else
{
snprintf(el_reg.sName, sizeof(el_reg.sName), "dxs_lib");
el_reg.nType = DXS_LIB_DEV_TYPE;
el_reg.nDevNum = pDev->nDevNum;
ret = ioctl(pDev->el_fd, EL_REGISTER, (int32_t)&el_reg);
if (ret == IFX_SUCCESS)
{
IFX_char_t *pCmd ="echo \"*\" > /proc/driver/el/logs/all";
FILE *el_pipe_fd;
el_pipe_fd = popen(pCmd, "r");
if (!el_pipe_fd)
{
return;
}
pclose(el_pipe_fd);
}
}
}
static void dxs_el_unregister(DXS_DEVICE_t *pDev)
{
EL_IoctlRegister_t el_reg;
snprintf(el_reg.sName, sizeof(el_reg.sName), "dxs_lib");
el_reg.nType = DXS_LIB_DEV_TYPE;
el_reg.nDevNum = pDev->nDevNum;
if (pDev->el_fd > 0)
{
ioctl(pDev->el_fd, EL_UNREGISTER, (int32_t)&el_reg);
}
}
#endif
/**
Function dxs_caps_init
\param dev - device number
*/
static void *dxs_caps_init(uint8_t dev)
{
DXS_Dev_Caps_t *p;
if (dev >= DXS_MAX_DEVICES)
return (void *)NULL;
p = &dxs_caps[dev];
p->flag = 0;
p->fw_vers.CMD = CMD_EOP;
p->fw_vers.MOD = MOD_SYS;
p->fw_vers.ECMD = DXS_FW_SYS_VERS_ECMD;
p->fw_vers.LENGTH = DXS_FW_SYS_VERS_LENGTH;
p->fw_caps.CMD = CMD_EOP;
p->fw_caps.MOD = MOD_SYS;
p->fw_caps.ECMD = DXS_FW_SYS_CAPS_ECMD;
p->fw_caps.LENGTH = DXS_FW_SYS_CAPS_LENGTH;
p->fw_sys_ctrl.CMD = CMD_EOP;
p->fw_sys_ctrl.MOD = MOD_SYS;
p->fw_sys_ctrl.ECMD = DXS_FW_SYS_Control_ECMD;
p->fw_sys_ctrl.LENGTH = DXS_FW_SYS_Control_LENGTH;
p->flag |= DXS_DEV_CAPS_INITIALIZED;
return (void *)p;
}
/**
Function dxs_caps_vers_update
\param pDev - pointer to DXS device structure
\return
- DXS_status_t
*/
int32_t dxs_caps_vers_update(DXS_DEVICE_t *pDev)
{
DXS_Dev_Caps_t *p;
int32_t err;
if (pDev == NULL)
{
DXS_RETURN(DXS_statusInvalidParam);
}
p = (DXS_Dev_Caps_t *)pDev->caps;
if (!(p->flag & DXS_DEV_CAPS_INITIALIZED))
{
DXS_RETURN(DXS_statusNotInitResource);
}
if (!(p->flag & DXS_DEV_CAPS_UPDATED))
{
err = CmdRead(pDev, (uint32_t *)&p->fw_caps, (uint32_t *)&p->fw_caps);
if (err)
{
DXS_RETURN(DXS_statusCapVersUpdateError);
}
err = CmdRead(pDev, (uint32_t *)&p->fw_vers, (uint32_t *)&p->fw_vers);
if (err)
{
DXS_RETURN(DXS_statusCapVersUpdateError);
}
/* update device ROM version */
pDev->rom_mask_ver = p->fw_vers.MAJ & 0x7F;
if (p->fw_vers.DEV == 0x9)
{
/* XS_VQFN-68_ES DXS Engineering Sample (A11 design)
in PG-VQFN-68 package */
p->pack = DXS_PACKAGE_VQFN68;
if (p->fw_vers.CH == 0)
{
p->dev = DXS_DEV_PEF32002_A11;
pDev->nChannels = 2;
}
else
{
p->dev = DXS_DEV_PEF32001_A11;
pDev->nChannels = 1;
}
}
else if (p->fw_vers.DEV == 0xA)
{
/* XS_VQFN-68_V11 DXS V1.1 (A12 design)
in PG-VQFN-68 package */
p->pack = DXS_PACKAGE_VQFN68;
if (p->fw_vers.CH == 0)
{
p->dev = DXS_DEV_PEF32002_A12;
pDev->nChannels = 2;
}
else
{
p->dev = DXS_DEV_PEF32001_A12;
pDev->nChannels = 1;
}
}
else if (p->fw_vers.DEV == 0x2A)
{
/* XC_VQFN-68_V11 DXC2 V1.1 (A12 design)
in PG-VQFN-68 package, only 2 channel version */
p->pack = DXS_PACKAGE_VQFN68;
p->dev = DXC_DEV_PEF31002_A12;
pDev->nChannels = 2;
}
else if (p->fw_vers.DEV == 0x49)
{
/* XS_VQFN-48_ES DXS1 Engineering Sample (A11 design)
in PG-VQFN-48 package */
p->pack = DXS_PACKAGE_VQFN48;
p->dev = DXS_DEV_PEF32001_A11;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0x4A)
{
/* XS_VQFN-48_V11 DXS1 V1.1 (A12 design)
in PG-VQFN-48 package */
p->pack = DXS_PACKAGE_VQFN48;
p->dev = DXS_DEV_PEF32001_A12;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0x6A)
{
/* XC_VQFN-48_V11 DXC1 V1.1 (A12 design)
in PG-VQFN-48 package */
p->pack = DXS_PACKAGE_VQFN48;
p->dev = DXC_DEV_PEF31001_A12;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0x0B)
{
/* XS_VQFN-68_V12 DXS2 V1.2 (A13 design)
in PG-VQFN-68 package */
p->pack = DXS_PACKAGE_VQFN68;
p->dev = DXS_DEV_PEF32002_V12_A13;
pDev->nChannels = 2;
}
else if (p->fw_vers.DEV == 0x2B)
{
/* XC_VQFN-68_V12 DXC2 V1.2 (A13 design)
in PG-VQFN-68 package */
p->pack = DXS_PACKAGE_VQFN68;
p->dev = DXC_DEV_PEF31002_V12_A13;
pDev->nChannels = 2;
}
else if (p->fw_vers.DEV == 0x8C)
{
/* XS_VQFN-44_V12 DXS1 V1.2
(A11 new codec design) in PG-VQFN-44 package */
p->pack = DXS_PACKAGE_VQFN44;
p->dev = DXS_DEV_PEF32001_V12_A11;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0xAC)
{
/* XC_VQFN-44_V12 DXC1 V1.2
(A11 new codec design) in PG-VQFN-44 package */
p->pack = DXS_PACKAGE_VQFN44;
p->dev = DXC_DEV_PEF31001_V12_A11;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0x4C)
{
/* XS_VQFN-48_V12 DXS1 V1.2
(A11 new codec design) in PG-VQFN-48 package */
p->pack = DXS_PACKAGE_VQFN48;
p->dev = DXS_DEV_PEF32001_V12_A11;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0x6C)
{
/* XC_VQFN-48_V12 DXC1 V1.2
(A11 new codec design) in PG-VQFN-48 package */
p->pack = DXS_PACKAGE_VQFN48;
p->dev = DXC_DEV_PEF31001_V12_A11;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0x0C)
{
/* XS_VQFN-68_V12 DXS1 V1.2
(A11 new codec design) in PG-VQFN-68 package */
p->pack = DXS_PACKAGE_VQFN68;
p->dev = DXS_DEV_PEF32001_V12_A11;
pDev->nChannels = 1;
}
else if (p->fw_vers.DEV == 0x2C)
{
/* XC_VQFN-68_V12 DXC1 V1.2
(A11 new codec design) in PG-VQFN-68 package */
p->pack = DXS_PACKAGE_VQFN68;
p->dev = DXC_DEV_PEF31001_V12_A11;
pDev->nChannels = 1;
}
else
{
p->pack = DXS_PACKAGE_UNKNOWN;
p->dev = DXS_DEV_UNKNOWN;
/* default for unfused device */
pDev->nChannels = 1;
}
p->flag |= DXS_DEV_CAPS_UPDATED;
}
return DXS_statusOk;
}
/**
Function dxs_caps_vers_forget
\param pDev - pointer to DXS device structure
\return
- DXS_status_t
*/
int32_t dxs_caps_vers_forget(DXS_DEVICE_t *pDev)
{
DXS_Dev_Caps_t *p;
if (pDev == NULL)
{
DXS_RETURN(DXS_statusInvalidParam);
}
p = (DXS_Dev_Caps_t *)pDev->caps;
p->flag &= ~DXS_DEV_CAPS_UPDATED;
return DXS_statusOk;
}
/**
Function dxs_get_dev
\param dxs - device number
\return
- pointer to DxS device structure
*/
DXS_DEVICE_t *dxs_get_dev (uint8_t dxs)
{
if (dxs >= DXS_MAX_DEVICES)
return NULL;
return &dxs_devices[dxs];
}
/**
Calculate CRC-8-CCITT. POLYNOMIAL = 0x07
\param pData Pointer to data for CRC calculation
\param nLength Length of data buffer
\return
Calculated CRC value.
*/
uint8_t dxs_CRC_8_CCITT(uint8_t *pData, uint32_t nLength)
{
uint8_t nCRC = 0;
int32_t i, j;
/* Perform modulo-2 division, a byte at a time. */
for (i = 0; i < nLength; i++)
{
/* Bring the next byte into the nCRC. */
nCRC ^= pData[i];
/* Perform modulo-2 division, a bit at a time. */
for (j = 8; j > 0; j--)
{
/* Try to divide the current data bit. */
if (nCRC & 0x80)
nCRC = (nCRC << 1) ^ 0x07;
else
nCRC = (nCRC << 1);
}
}
return nCRC;
}
/**
Function dxs_exit
\param pDev - pointer to DXS device structure
*/
int32_t dxs_exit(DXS_DEVICE_t *pDev)
{
uint8_t ch;
int32_t ret = DXS_statusOk;
if (pDev->flags & DXS_DEV_INITIALIZED)
{
/* DCDC HW specific deinit */
DXS_DCDC_HW_Exit(pDev);
if (pDev->irqNumber == -1)
{
/* stop polling */
dxs_polling_timer_stop();
}
else
{
/* uninstall interrupt handler */
dxs_interrupt_exit();
}
/* stop obx handling thread */
dxs_outbox_handler_exit(pDev);
pDev->flags &= ~DXS_DEV_OBX_HND_INITIALIZED;
/* uninitialize event memory pool */
dxs_event_pool_exit(pDev);
/* uninitialize message queues */
fifo_destroy(pDev->event_queue);
fifo_destroy(pDev->cmd_obx_queue);
/* close SPI interface */
dxs_spi_linux_exit(pDev->spidev);
pDev->flags &= ~DXS_DEV_ACCESS_INITIALIZED;
/* delete mbx access mutex */
ret = pthread_mutex_unlock(&pDev->mtxMbxAcc);
if (ret != 0)
DXS_ERROR_PUSH(ret);
ret = pthread_mutex_destroy(&pDev->mtxMbxAcc);
if (ret != 0)
DXS_ERROR_PUSH(ret);
sem_destroy(&pDev->mtxPatchDwld);
#ifdef DXS_FEAT_UTD
/* delete UTD mutex */
dxs_sig_utd_mtx_destroy();
#endif /* DXS_FEAT_UTD */
/* close channel resources */
for (ch = 0; ch < pDev->nChannels; ch++)
{
DXS_CHANNEL_t *pCh = &pDev->pChannel[ch];
#ifdef DXS_FEAT_HSM
DXS_Dial_Cleanup(pCh);
#endif
/* cleanup only for SDD resource */
ret = DXS_SDD_ChExit(pCh);
if (ret != DXS_statusOk)
DXS_ERROR_PUSH(ret);
}
#ifdef EVENT_LOGGER_DEBUG
dxs_el_unregister(pDev);
#endif /* EVENT_LOGGER_DEBUG */
pDev->flags &= ~DXS_DEV_INITIALIZED;
}
DXS_RETURN(ret);
}
/**
Default initialization of DXS registers.
Enable the required interrupts in the register interface.
\param pDev pointer to the device structure
\return
- DXS_statusOk
- DXS_statusSpiAccError
*/
static int32_t dxs_default_reg_init(DXS_DEVICE_t *pDev)
{
int32_t ret = DXS_statusOk;
uint16_t nRegHostIen1, nRegHostIen2;
/*
Enable the interrupts OBX_RDY and ERR.
*/
nRegHostIen1 = DXS_REG_IEN1_RESET;
nRegHostIen1 |= DXS_REG_IEN1_OBX_RDY;
nRegHostIen1 |= DXS_REG_IEN1_ERR;
ret = DXS_RegWrite(pDev, DXS_REG_IEN1, nRegHostIen1);
if (ret != DXS_statusOk)
DXS_RETURN(ret);
/*
Enable the interrupts OBX_UFL and IBX_OFL.
*/
nRegHostIen2 = DXS_REG_IEN2_RESET;
nRegHostIen2 |= DXS_REG_IEN2_OBX_UFL;
nRegHostIen2 |= DXS_REG_IEN2_IBX_OFL;
ret = DXS_RegWrite(pDev, DXS_REG_IEN2, nRegHostIen2);
DXS_RETURN(ret);
}
/**
Function dxs_init
\param pDev - pointer to DXS device structure
\param chipSelect - CS number
\param irqNumber - IRQ line number
\param dcdcType - DCDC variant handled by DXS_DCDC_Var_t type
\param dev - device number
\return
- DXS_status_t
*/
/*
* should return either 0 or -1
*/
int32_t dxs_init(DXS_DEVICE_t *pDev, uint8_t chipSelect, int32_t irqNumber,
uint8_t dcdcType, uint8_t access, uint8_t dev)
{
int32_t ret = DXS_statusOk, i;
#ifdef DXS_FEAT_HSM
DXS_status_t status;
#endif
uint8_t ch;
if (access >= DXS_ACCESS_LAST)
{
DXS_RETURN(DXS_statusInvalidParam);
}
if (dev >= DXS_MAX_DEVICES)
{
DXS_RETURN(DXS_statusInvalidParam);
}
for (i=0; i<DXS_MAX_DEVICES; i++)
{
DXS_DEVICE_t *pdev = dxs_get_dev(i);
if (pdev->flags & DXS_DEV_INITIALIZED && pdev->dcdcType != dcdcType)
{
/* provided dcdcType does not match
with previously initialized devices */
DXS_RETURN(DXS_statusInvalidParam);
}
}
ret = dxs_exit(pDev);
if (ret != DXS_statusOk)
{
DXS_RETURN(DXS_statusDevInitFailed);
}
pDev->nDevNum = dev;
pDev->chipSelect = chipSelect;
pDev->irqNumber = irqNumber;
pDev->dcdcType = dcdcType;
pDev->access = access;
pthread_mutex_init(&pDev->mtxMbxAcc, NULL);
pDev->nMbxCachedCbiLen = 0;
#ifdef EVENT_LOGGER_DEBUG
dxs_el_register(pDev);
#endif
/* open SPI interface */
pDev->spidev = dxs_spi_linux_init(chipSelect, access);
if (pDev->spidev > 0)
{
pDev->flags |= DXS_DEV_ACCESS_INITIALIZED;
}
else
{
DXS_RETURN(DXS_statusSpiOpenError);
}
/* TODO: light chip access test + error code if failed */
/* Reset the DXS controller to bring the chip into the default state.
The data structures of the driver will be initialized to the same
known default state.*/
dxs_controller_reset(pDev);
/* initialize message queues */
pDev->event_queue = fifo_init (20);
if (NULL == pDev->event_queue)
{
DXS_RETURN(DXS_statusMsgQueueCreatError);
}
pDev->cmd_obx_queue = fifo_init (64);
if (NULL == pDev->cmd_obx_queue)
{
DXS_RETURN(DXS_statusMsgQueueCreatError);
}
/* initialize event memory pool */
if (DXS_statusOk != dxs_event_pool_init(pDev))
{
DXS_RETURN(DXS_statusMpoolInitError);
}
/* start obx handling thread */
ret = dxs_outbox_handler_init(pDev);
if (ret != DXS_statusOk)
{
DXS_RETURN(DXS_statusObxHandlerStartError);
}
pDev->flags |= DXS_DEV_OBX_HND_INITIALIZED;
/* initialize device resources */
pDev->caps = dxs_caps_init(dev);
pDev->pcm = dxs_pcm_dev_init(dev);
if (pDev->access == DXS_ACCESS_CSI)
{
/* default configuration of CSI Master */
uint16_t nCSIMasterCFG =
(DXS_REG_CSI_M_CFG_PAUSE_DEFAULT | DXS_REG_CSI_M_CFG_PDEMUX);
ret = DXS_RegWrite(pDev, DXS_REG_CSI_M_CFG, nCSIMasterCFG);
if (ret != DXS_statusOk)
{
DXS_RETURN(ret);
}
}
#ifdef DXS_FEAT_GPIO
pDev->gpio = DXS_GPIO_DevInit(dev);
#endif
/* start device polling */
if (pDev->irqNumber != 255 &&
(pDev->irqNumber == -1 || dxs_interrupt_init(pDev) != DXS_statusOk))
{
dxs_polling_timer_start();
}
/* In IRQ as well as polling mode set the interrupt masks. */
ret = dxs_default_reg_init(pDev);
if (ret != DXS_statusOk)
{
DXS_RETURN(ret);
}
/* read capabilities and version from device -
must be after polling start or interrupt enable */
dxs_caps_vers_update(pDev);
#ifdef DXS_FEAT_UTD
/* initialize UTD mutex */
dxs_sig_utd_mtx_init();
#endif /* DXS_FEAT_UTD */
/* initialize channel resources -
must be after capabilities read */
for (ch = 0; ch < pDev->nChannels; ch++)
{
DXS_CHANNEL_t *pCh = &pDev->pChannel[ch];
pCh->pParent = pDev;
pCh->nCh = ch;
pCh->pcm = dxs_pcm_ch_init(pDev->nDevNum, ch);
pCh->sdd = DXS_SDD_ChInit(pDev->nDevNum, ch);
pCh->sig = dxs_sig_ch_init(pDev->nDevNum, ch);
#ifdef DXS_FEAT_HSM
status = DXS_Dial_Initialise_Unprot(pCh);
if (status != DXS_statusOk)
{
DXS_RETURN(status);
}
#endif
#ifdef DXS_FEAT_CID
/* cleanup static data */
DXS_CID_Cleanup(pCh);
#endif
pCh->ring = DXS_Ring_ResInit(pCh);
DXS_EventMaskSetDefault(pCh);
}
/* From now on process all events. */
dxs_outbox_handler_enable(pDev);
/* patch download sync sem */
sem_init(&pDev->mtxPatchDwld, 0, 0);
pDev->bWaitingInPatchDwld = 0;
/* DCDC HW specific init */
DXS_DCDC_HW_Init(pDev);
pDev->flags |= DXS_DEV_INITIALIZED;
return DXS_statusOk;
}
/**
Function dxs_controller_reset
\param pDev - pointer to DXS device structure
\return
- DXS_status_t
*/
int32_t dxs_controller_reset(DXS_DEVICE_t *pDev)
{
int32_t ret = DXS_statusOk;
uint16_t nDxsRegBootCfg = 0,
nDxsRegBootInfo = 0,
nDxsRegCfg = 0;
/* Set the controller startup configuration in the Boot Configuration
Register to boot from ROM. */
nDxsRegBootCfg = DXS_REG_BCFG_ASC_ROM;
ret = DXS_RegWrite(pDev, DXS_REG_BCFG, nDxsRegBootCfg);
if (ret != DXS_statusOk)
{
/* errmsg: Setting of boot configuration register failed. */
ret = DXS_statusSetBootCfgErr;
}
/* Reset controller to start the boot. */
if (ret == DXS_statusOk)
{
nDxsRegCfg = DXS_REG_CFG_RST_RSTCORE|DXS_REG_CFG_8BIT_EN;
ret = DXS_RegWrite(pDev, DXS_REG_CFG, nDxsRegCfg);
if (ret != DXS_statusOk)
{
/* errmsg: Controller reset failed. */
ret = DXS_statusCtrlResErr;
}
}
/* Check success of the reset by reading the boot info register. */
if (ret == DXS_statusOk)
{
uint8_t loop = 10;
while (loop > 0)
{
struct timespec ts = {0, 2000000}; /* 2 ms */
nanosleep(&ts, NULL);
/* read the boot state indication */
ret = DXS_RegRead(pDev, DXS_REG_BINF, &nDxsRegBootInfo);
if ((ret == DXS_statusOk) &&
((nDxsRegBootInfo & DXS_REG_BINF_BOOTSTATE_MASK) >= 0x10))
{
break;
}
loop--;
}
if (loop == 0)
{
/* errmsg: Firmware download timeout. */
ret = DXS_statusFwDwldTimeout;
}
}
DXS_RETURN(ret);
}
/**
Function dxs_caps_read
\param pDev - pointer to DXS device structure
\param pCap - pointer to DXS_Caps_t structure
\return
- DXS_status_t
*/
int32_t dxs_caps_read(DXS_DEVICE_t *pDev, DXS_Caps_t *pCap)
{
DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
if (DXS_statusOk == dxs_caps_vers_update(pDev))
{
pCap->nChannels = pDev->nChannels;
pCap->nGR909 = p->fw_caps.GR909;
pCap->nACLM = p->fw_caps.ACLM;
pCap->nTTX = p->fw_caps.TTX;
pCap->nUTD = p->fw_caps.UTD;
pCap->nCID = p->fw_caps.CID;
pCap->nHowler = p->fw_caps.HOWLER;
}
else
{
DXS_RETURN(DXS_statusCapVersUpdateError);
}
return DXS_statusOk;
}
/**
Function dxs_vers_read
\param pDev - pointer to DXS device structure
\param pVersion - pointer to DXS_Version_t structure
\return
- DXS_status_t
*/
int32_t dxs_vers_read(DXS_DEVICE_t *pDev, DXS_Version_t *pVersion)
{
DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
if (DXS_statusOk == dxs_caps_vers_update(pDev))
{
pVersion->device = p->dev;
pVersion->package = p->pack;
pVersion->fw_maj = p->fw_vers.MAJ;
pVersion->fw_min = p->fw_vers.MIN;
pVersion->fw_hfix = p->fw_vers.HF;
pVersion->fw_time = p->fw_vers.TIME;
pVersion->lib_ver = DXS_LIB_VERSION;
pVersion->api_ver = DXS_API_VERSION;
}
else
{
DXS_RETURN(DXS_statusCapVersUpdateError);
}
return DXS_statusOk;
}
/**
Function dxs_sleep
\param pDev - pointer to DXS device structure
\param enable - enable
\return
- DXS_status_t
*/
int32_t dxs_sleep(DXS_DEVICE_t *pDev, uint8_t enable)
{
DXS_Dev_Caps_t *p;
int32_t ret = DXS_statusOk;
if (pDev == NULL || enable > 1)
{
DXS_RETURN(DXS_statusInvalidParam);
}
p = (DXS_Dev_Caps_t *)pDev->caps;
if (!(p->flag & DXS_DEV_CAPS_INITIALIZED))
{
DXS_RETURN(DXS_statusNotInitResource);
}
if (!(p->flag & DXS_DEV_SYS_CTRL_UPDATED))
{
ret = CmdRead(pDev, (uint32_t *)&p->fw_sys_ctrl, (uint32_t *)&p->fw_sys_ctrl);
if (ret != DXS_statusOk)
{
DXS_RETURN(ret);
}
p->flag |= DXS_DEV_SYS_CTRL_UPDATED;
}
/* sleep mode is not allowed for shared DCDC */
if (pDev->dcdcType == DXS_DCDC_IFB12CH8 && enable)
{
DXS_RETURN(DXS_statusSleepModeNotAllowed);
}
/* update command */
if (enable != p->fw_sys_ctrl.SE)
{
p->fw_sys_ctrl.SE = enable;
ret = CmdWrite(pDev, (uint32_t *)&p->fw_sys_ctrl);
}
DXS_RETURN(ret);
}
/**
Check if a particular feature is supported by the device
\param pDev - pointer to DXS device structure
\param cap - feature enumerator \ref e_DXS_DevCaps
\return
- 1 if a featire is supported, 0 if not
*/
int32_t DXS_IsFeatureSupported(DXS_DEVICE_t *pDev, enum e_DXS_DevCaps cap)
{
DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
DXS_FW_SYS_CAPS_t *pCap = &p->fw_caps;
uint32_t sys_read_caps_I1 = *((uint32_t *)pCap + 1);
if (sys_read_caps_I1 & (1 << cap))
return 1;
return 0;
}
/**
Switch on the Charge Pump
\param pDev - pointer to DXS device structure
\return
- DXS_status_t
*/
int32_t DXS_ChargePumpSwitchOn(DXS_DEVICE_t *pDev)
{
DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
DXS_FW_SYS_Control_t *pSysCtrl = &p->fw_sys_ctrl;
int32_t ret = DXS_statusOk;
/* for IFB12CH8 apply the configuration only for the device
that owns a master channel */
if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
{
DXS_CHANNEL_t *pCh, *pChMaster;
uint8_t i = 0, master_found = 0;
if ((pChMaster=DXS_DCDC_HW_SharedDcDcMasterChGetInt(pDev)) != NULL)
{
for (pCh=&pDev->pChannel[0],i=0; i < pDev->nChannels; i++, pCh++)
{
if (pCh == pChMaster)
{
master_found = 1;
break;
}
}
if (!master_found)
return DXS_statusOk;
}
}
if (pSysCtrl->CP_EN != 1)
{
pSysCtrl->CP_VOLT = DXS_FW_SYS_Control_CP_VOLT_5_0V;
pSysCtrl->CP_EN = 1;
ret = CmdWrite(pDev, (uint32_t *)pSysCtrl);
}
DXS_RETURN(ret);
}
#if 0
/**
Switch off the Charge Pump
\param pDev - pointer to DXS device structure
\return
- DXS_status_t
*/
int32_t DXS_ChargePumpSwitchOff(DXS_DEVICE_t *pDev)
{
DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
DXS_FW_SYS_Control_t *pSysCtrl = &p->fw_sys_ctrl;
int32_t ret = DXS_statusOk;
/* for IFB12CH8 apply the configuration only for the device
that owns a master channel */
if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
{
DXS_CHANNEL_t *pCh, *pChMaster;
uint8_t i = 0, master_found = 0;
if ((pChMaster=DXS_DCDC_HW_SharedDcDcMasterChGetInt(pDev)) != NULL)
{
for (pCh=&pDev->pChannel[0],i=0; i < pDev->nChannels; i++, pCh++)
{
if (pCh == pChMaster)
{
master_found = 1;
break;
}
}
if (!master_found)
return DXS_statusOk;
}
}
if (pSysCtrl->CP_EN != 0)
{
pSysCtrl->CP_EN = 0;
ret = CmdWrite(pDev, (uint32_t *)pSysCtrl);
}
DXS_RETURN(ret);
}
#endif /* 0 */
/**
Switch on/off Clock Failure handling
\param pDev - pointer to DXS device structure
\param enable - 0 or 1
\return
- DXS_status_t
*/
int32_t DXS_CfEsdSwitch (DXS_DEVICE_t *pDev, uint8_t enable)
{
DXS_Dev_Caps_t *p;
int32_t ret = DXS_statusOk;
uint8_t plim;
if (pDev == NULL || enable > 1)
{
DXS_RETURN(DXS_statusInvalidParam);
}
p = (DXS_Dev_Caps_t *)pDev->caps;
if (!(p->flag & DXS_DEV_CAPS_INITIALIZED))
{
DXS_RETURN(DXS_statusNotInitResource);
}
if (!(p->flag & DXS_DEV_SYS_CTRL_UPDATED))
{
ret = CmdRead(pDev, (uint32_t *)&p->fw_sys_ctrl, (uint32_t *)&p->fw_sys_ctrl);
if (ret != DXS_statusOk)
{
DXS_RETURN(ret);
}
p->flag |= DXS_DEV_SYS_CTRL_UPDATED;
}
plim = enable ? 0 : 1;
if (p->fw_sys_ctrl.PLIM != plim || p->fw_sys_ctrl.SYCLKE != enable)
{
p->fw_sys_ctrl.PLIM = plim;
p->fw_sys_ctrl.SYCLKE = enable;
ret = CmdWrite(pDev, (uint32_t *)&p->fw_sys_ctrl);
}
DXS_RETURN(ret);
}
/**
Get device info
\param pDev - pointer to DXS device structure
\param pROM_id - ROM mask ID (output)
\param pChannels - number of channels (output)
\return
- DXS_status_t
*/
void DXS_DevInfoGet (DXS_DEVICE_t *pDev, uint8_t *pROM_id,
uint8_t *pChannels)
{
DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
*pROM_id = p->fw_vers.MAJ & 0x7f;
*pChannels = p->fw_vers.CH ? 1 : 2;
}