ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/services/dxslic/api_lib/src/dxs_init.c b/marvell/services/dxslic/api_lib/src/dxs_init.c
new file mode 100644
index 0000000..e5ab2eb
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_init.c
@@ -0,0 +1,1241 @@
+/******************************************************************************
+
+  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;
+}