| /****************************************************************************** |
| |
| 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; |
| } |