/**************************************************************************//**
 * @brief   Setup clocks necessary to drive RTC/RTCC for EXTCOM GPIO pin.
 *
 * @return  N/A
 *****************************************************************************/
static void palClockSetup(CMU_Clock_TypeDef clock)
{
  /* Enable LE domain registers */
  CMU_ClockEnable(cmuClock_CORELE, true);

#if ( defined(PAL_CLOCK_RTC) && defined(PAL_RTC_CLOCK_LFXO) ) \
    || ( defined(PAL_CLOCK_RTCC) && defined(PAL_RTCC_CLOCK_LFXO) )
  /* LFA with LFXO setup is relatively time consuming. Therefore, check if it
     already enabled before calling. */
  if ( !(CMU->STATUS & CMU_STATUS_LFXOENS) )
  {
    CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
  }
  if ( cmuSelect_LFXO != CMU_ClockSelectGet(clock) )
  {
    CMU_ClockSelectSet(clock, cmuSelect_LFXO);
  }
#elif ( defined(PAL_CLOCK_RTC) && defined(PAL_RTC_CLOCK_LFRCO) ) \
    || ( defined(PAL_CLOCK_RTCC) && defined(PAL_RTCC_CLOCK_LFRCO) )
  /* Enable LF(A|E)CLK in CMU (will also enable LFRCO oscillator if not enabled) */
  CMU_ClockSelectSet(clock, cmuSelect_LFRCO);
#elif ( defined(PAL_CLOCK_RTC) && defined(PAL_RTC_CLOCK_ULFRCO) ) \
    || ( defined(PAL_CLOCK_RTCC) && defined(PAL_RTCC_CLOCK_ULFRCO) )
  /* Enable LF(A|E)CLK in CMU (will also enable ULFRCO oscillator if not enabled) */
  CMU_ClockSelectSet(clock, cmuSelect_ULFRCO);
#else
#error No clock source for RTC defined.
#endif
}
Esempio n. 2
0
/**************************************************************************//**
 * @brief Enables LFACLK and selects LFXO as clock source for RTC
 *        Sets up the RTC to generate an interrupt every second.
 *****************************************************************************/
static void rtcSetup(unsigned int frequency)
{
  RTC_Init_TypeDef rtcInit = RTC_INIT_DEFAULT;

  /* Enable LE domain registers */
  if ( !( CMU->HFCORECLKEN0 & CMU_HFCORECLKEN0_LE) )
  {
    CMU_ClockEnable(cmuClock_CORELE, true);
  }

#ifdef PAL_RTC_CLOCK_LFXO
  /* LFA with LFXO setup is relatively time consuming. Therefore, check if it
     already enabled before calling. */
  if ( !(CMU->STATUS & CMU_STATUS_LFXOENS) )
  {
    CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
  }
  if ( cmuSelect_LFXO != CMU_ClockSelectGet(cmuClock_LFA) )
  {
    CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
  }
#elif defined PAL_RTC_CLOCK_LFRCO
  /* Enable LFACLK in CMU (will also enable LFRCO oscillator if not enabled) */
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
#elif defined PAL_RTC_CLOCK_ULFRCO
  /* Enable LFACLK in CMU (will also enable ULFRCO oscillator if not enabled) */
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_ULFRCO);
#else
#error No clock source for RTC defined.
#endif

  /* Set the prescaler. */
  CMU_ClockDivSet( cmuClock_RTC, cmuClkDiv_1 );

  /* Enable RTC clock */
  CMU_ClockEnable(cmuClock_RTC, true);

  /* Initialize RTC */
  rtcInit.enable   = false;  /* Do not start RTC after initialization is complete. */
  rtcInit.debugRun = false;  /* Halt RTC when debugging. */
  rtcInit.comp0Top = true;   /* Wrap around on COMP0 match. */
  RTC_Init(&rtcInit);

  /* Interrupt at given frequency. */
  RTC_CompareSet(0, (CMU_ClockFreqGet(cmuClock_RTC) / frequency) - 1 );

  /* Enable interrupt */
  NVIC_EnableIRQ(RTC_IRQn);
  RTC_IntEnable(RTC_IEN_COMP0);

  /* Start Counter */
  RTC_Enable(true);
}
Esempio n. 3
0
/***************************************************************************//**
 * @brief
 *   Initializes USB device hardware and internal protocol stack data structures,
 *   then connects the data-line (D+ or D-) pullup resistor to signal host that
 *   enumeration can begin.
 *
 * @note
 *   You may later use @ref USBD_Disconnect() and @ref USBD_Connect() to force
 *   reenumeration.
 *
 * @param[in] p
 *   Pointer to device initialization struct. See @ref USBD_Init_TypeDef.
 *
 * @return
 *   @ref USB_STATUS_OK on success, else an appropriate error code.
 ******************************************************************************/
int USBD_Init( const USBD_Init_TypeDef *p )
{
  USBD_Ep_TypeDef *ep;
  CORE_DECLARE_IRQ_STATE;

#if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
  /* Devices supporting crystal-less USB can use HFRCO or HFXO as core clock. */
  /* All other devices must use HFXO as core clock.                           */
  if ( CMU_ClockSelectGet( cmuClock_HF ) != cmuSelect_HFXO )
  {
    CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
  }
#endif

#if !defined( CMU_OSCENCMD_USHFRCOEN )
#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
  CMU_OscillatorEnable(cmuOsc_LFXO, true, false);
#else
  CMU_OscillatorEnable(cmuOsc_LFRCO, true, false);
#endif

#else
  CMU_ClockEnable(cmuClock_CORELE, true);
  /* LFC clock is needed to detect USB suspend when LEMIDLE is activated. */
#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
  CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFXO);
#else
  CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFRCO);
#endif
  CMU_ClockEnable(cmuClock_USBLE, true);
#endif

  USBTIMER_Init();

  memset( dev, 0, sizeof( USBD_Device_TypeDef ) );

  dev->setup                = dev->setupPkt;
  dev->state                = USBD_STATE_LASTMARKER;
  dev->savedState           = USBD_STATE_NONE;
  dev->lastState            = USBD_STATE_NONE;
  dev->callbacks            = p->callbacks;
  dev->remoteWakeupEnabled  = false;

  /* Initialize EP0 */

  ep                 = &dev->ep[ 0 ];
  ep->in             = false;
  ep->buf            = NULL;
  ep->num            = 0;
  ep->mask           = 1;
  ep->addr           = 0;
  ep->type           = USB_EPTYPE_CTRL;
  ep->txFifoNum      = 0;

  /* FIXME! */
  ep->packetSize     = 64;
  dev->ep0MpsCode = _USB_DOEP0CTL_MPS_64B;

  ep->remaining      = 0;
  ep->xferred        = 0;
  ep->state          = D_EP_IDLE;
  ep->xferCompleteCb = NULL;
  ep->fifoSize       = ep->packetSize / 4;

  totalTxFifoSize = ep->fifoSize * p->bufferingMultiplier[ 0 ];
  totalRxFifoSize = (ep->fifoSize + 1) * p->bufferingMultiplier[ 0 ];

  /* Rx-FIFO size: SETUP packets : 4*n + 6    n=#CTRL EP's
   *               GOTNAK        : 1
   *               Status info   : 2*n        n=#OUT EP's (EP0 included) in HW
   */
  totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );

  CORE_ENTER_CRITICAL();

  /* Enable USB clock */
  CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC;

#if defined( CMU_OSCENCMD_USHFRCOEN )
  CMU->USHFRCOCONF = CMU_USHFRCOCONF_BAND_48MHZ;
  CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_USHFRCO );

  /* Enable USHFRCO Clock Recovery mode. */
  CMU->USBCRCTRL |= CMU_USBCRCTRL_EN;

  /* Turn on Low Energy Mode (LEM) features. */
  USB->CTRL = USB_CTRL_LEMOSCCTRL_GATE
              | USB_CTRL_LEMIDLEEN
              | USB_CTRL_LEMPHYCTRL;
#else
  CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK );
#endif

  USBHAL_DisableGlobalInt();

  if ( USBDHAL_CoreInit( totalRxFifoSize, totalTxFifoSize ) == USB_STATUS_OK )
  {
    USBDHAL_EnableUsbResetAndSuspendInt();
    USBHAL_EnableGlobalInt();
    NVIC_ClearPendingIRQ( USB_IRQn );
    NVIC_EnableIRQ( USB_IRQn );
  }
  else
  {
    CORE_EXIT_CRITICAL();
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), FIFO setup error" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
  if ( USBHAL_VbusIsOn() )
  {
    USBD_SetUsbState( USBD_STATE_POWERED );
  }
  else
#endif
  {
    USBD_SetUsbState( USBD_STATE_NONE );
  }

  CORE_EXIT_CRITICAL();
  return USB_STATUS_OK;
}
Esempio n. 4
0
void main ()
{
  uint32_t lfa_Hz;
  uint16_t reset_cause;
  int sleep_mode = 0;
  uint32_t burtc_ctrl;

  CHIP_Init();
  reset_cause = RMU->RSTCAUSE;
  RMU_ResetCauseClear();
#if ! defined(_EFM32_ZERO_FAMILY)
  BSPACM_CORE_BITBAND_PERIPH(RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT) = 0;
#endif
  SystemCoreClockUpdate();
  vBSPACMledConfigure();

  setvbuf(stdout, NULL, _IONBF, 0);

  BSPACM_CORE_ENABLE_INTERRUPT();

  printf("\n" __DATE__ " " __TIME__ "\n");
  printf("System clock %lu Hz\n", SystemCoreClock);
  {
    int i = sizeof(xResetCause)/sizeof(*xResetCause);

    printf("Reset cause [%04x]:", reset_cause);
    while (0 <= --i) {
      const sResetCause * const rcp = xResetCause + i;
      if (rcp->value == (reset_cause & rcp->mask)) {
        printf(" %s", rcp->name);
      }
    }
    printf("\nRMU CTRL %lx\n", RMU->CTRL);
  }

  /* Enable low-energy support. */
  CMU_ClockEnable(cmuClock_CORELE, true);
  BURTC_Enable(true);

  if (MAGIC != retained_state->magic) {
    memset(retained_state, 0, sizeof(*retained_state));
    retained_state->magic = MAGIC;
    printf("Resetting retained state\n");
  }
  ++retained_state->boots;
  printf("Boot count %lu\n", retained_state->boots);

  printf("BURTC clock source: ");
#if (WITH_ULFRCO - 0)
  /* Use ULFRCO, which enables EM4 wakeup but is pretty inaccurate. */
  printf("ULFRCO\n");
  /* NB: DIV2 means 1 kHz instead of 2 kHz */
  burtc_ctrl = BURTC_CTRL_CLKSEL_ULFRCO | BURTC_CTRL_PRESC_DIV2;
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_ULFRCO);
  lfa_Hz = CMU_ClockFreqGet(cmuClock_LFA);
  {
    EMU_EM4Init_TypeDef cfg = {
      .lockConfig = 1,
      .osc = EMU_EM4CONF_OSC_ULFRCO,
      .buRtcWakeup = 1,
      .vreg = 1,
    };
    EMU_EM4Init(&cfg);
  }
#elif (WITH_LFRCO - 0)
  printf("LFRCO/32\n");
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
  burtc_ctrl = BURTC_CTRL_CLKSEL_LFRCO | BURTC_CTRL_PRESC_DIV32;
  lfa_Hz = CMU_ClockFreqGet(cmuClock_LFA) / 32;
#else
  printf("LFXO/32\n");
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
  burtc_ctrl = BURTC_CTRL_CLKSEL_LFXO | BURTC_CTRL_PRESC_DIV32;
  lfa_Hz = CMU_ClockFreqGet(cmuClock_LFA) / 32;
#endif /* LFA source */
  printf("LFA clock at %lu Hz ; wake every %u seconds\n", lfa_Hz, WAKE_INTERVAL_S);

  /* Initialize BURTC. */
  if (! (RMU_RSTCAUSE_EM4WURST & reset_cause)) {
    printf("Initializing BURTC\n");
    BURTC->FREEZE = BURTC_FREEZE_REGFREEZE;
    BURTC->LPMODE = BURTC_LPMODE_LPMODE_DISABLE;
    BURTC->CTRL = burtc_ctrl /* CLKSEL + PRESC */
      | BURTC_CTRL_RSTEN
      | BURTC_CTRL_MODE_EM4EN
      ;
    BURTC->COMP0 = WAKE_INTERVAL_S * lfa_Hz;
    BURTC->IEN = BURTC_IF_COMP0;
    BURTC->CTRL &= ~BURTC_CTRL_RSTEN;
    BURTC->FREEZE = 0;
  } else {
    while (BURTC_SYNCBUSY_COMP0 & BURTC->SYNCBUSY) {
    }
    BURTC->COMP0 += WAKE_INTERVAL_S * lfa_Hz;
  }
  BURTC->IFC = BURTC_IFC_COMP0;
  NVIC_EnableIRQ(BURTC_IRQn);

  printf("BURTC CTRL %lx IEN %lx\n", BURTC->CTRL, BURTC->IEN);
  (void)iBSPACMperiphUARTflush(hBSPACMdefaultUART, eBSPACMperiphUARTfifoState_TX);
  while (1) {
    static const sBSPACMperiphUARTconfiguration cfg = { .speed_baud = 0 };
    printf("Sleeping in mode %u, %lu to %lu rtc_if %x or %lx\n", sleep_mode, BURTC->CNT, BURTC->COMP0, burtc_if, BURTC->IF);
    BSPACM_CORE_DISABLE_INTERRUPT();
    do {
      (void)iBSPACMperiphUARTflush(hBSPACMdefaultUART, eBSPACMperiphUARTfifoState_TX);
      hBSPACMperiphUARTconfigure(hBSPACMdefaultUART, 0);
      switch (sleep_mode) {
        case 0:
          while (! (BURTC_IF_COMP0 & BURTC->IF)) {
          }
          ++sleep_mode;
          break;
        case 1:
          EMU_EnterEM1();
          ++sleep_mode;
          break;
        case 2:
          EMU_EnterEM2(true);

          SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
          if (cmuSelect_ULFRCO == CMU_ClockSelectGet(cmuClock_LFA)) {
            ++sleep_mode;
          } else {
            sleep_mode = 0;
          }
          break;
        case 3:
          EMU_EnterEM3(true);
          SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
          if (cmuSelect_ULFRCO == CMU_ClockSelectGet(cmuClock_LFA)) {
            ++sleep_mode;
          } else {
            sleep_mode = 0;
          }
          break;
        case 4:
          EMU_EnterEM4();
          sleep_mode = 0;
          break;
      }
    } while (0);
    BSPACM_CORE_ENABLE_INTERRUPT();
    hBSPACMperiphUARTconfigure(hBSPACMdefaultUART, &cfg);
    while (BURTC_SYNCBUSY_COMP0 & BURTC->SYNCBUSY) {
    }
    BURTC->COMP0 += WAKE_INTERVAL_S * lfa_Hz;
    /* Giant Gecko
     *  Source    EM0    EM1    EM2     EM3    EM4
     * ULFRCO    2.5m   1.1m   622n    622n   450n
     */
  }

}
Esempio n. 5
0
/***************************************************************************//**
 * @brief
 *   Initializes USB device hardware and internal protocol stack data structures,
 *   then connects the data-line (D+ or D-) pullup resistor to signal host that
 *   enumeration can begin.
 *
 * @note
 *   You may later use @ref USBD_Disconnect() and @ref USBD_Connect() to force
 *   reenumeration.
 *
 * @param[in] p
 *   Pointer to device initialization struct. See @ref USBD_Init_TypeDef.
 *
 * @return
 *   @ref USB_STATUS_OK on success, else an appropriate error code.
 ******************************************************************************/
int USBD_Init( const USBD_Init_TypeDef *p )
{
  int numEps;
  USBD_Ep_TypeDef *ep;
  uint8_t txFifoNum;
  uint8_t *conf, *confEnd;
  USB_EndpointDescriptor_TypeDef *epd;
  USB_InterfaceDescriptor_TypeDef *id;
  uint32_t totalRxFifoSize, totalTxFifoSize, numInEps, numOutEps;

#if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
  /* Devices supporting crystal-less USB can use HFRCO or HFXO as core clock. */
  /* All other devices must use HFXO as core clock.                           */
  if ( CMU_ClockSelectGet( cmuClock_HF ) != cmuSelect_HFXO )
  {
    CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
  }
#endif

#if !defined( CMU_OSCENCMD_USHFRCOEN )
#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
  CMU_OscillatorEnable(cmuOsc_LFXO, true, false);
#else
  CMU_OscillatorEnable(cmuOsc_LFRCO, true, false);
#endif

#else
  CMU_ClockEnable(cmuClock_CORELE, true);
  /* LFC clock is needed to detect USB suspend when LEMIDLE is activated. */
#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
  CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFXO);
#else
  CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFRCO);
#endif
  CMU_ClockEnable(cmuClock_USBLE, true);
#endif

  USBTIMER_Init();

  memset( dev, 0, sizeof( USBD_Device_TypeDef ) );

  dev->setup                = dev->setupPkt;
  dev->deviceDescriptor     = p->deviceDescriptor;
  dev->configDescriptor     = (USB_ConfigurationDescriptor_TypeDef*)
                              p->configDescriptor;
  dev->stringDescriptors    = p->stringDescriptors;
  dev->numberOfStrings      = p->numberOfStrings;
  dev->state                = USBD_STATE_LASTMARKER;
  dev->savedState           = USBD_STATE_NONE;
  dev->lastState            = USBD_STATE_NONE;
  dev->callbacks            = p->callbacks;
  dev->remoteWakeupEnabled  = false;

  /* Initialize EP0 */

  ep                 = &dev->ep[ 0 ];
  ep->in             = false;
  ep->buf            = NULL;
  ep->num            = 0;
  ep->mask           = 1;
  ep->addr           = 0;
  ep->type           = USB_EPTYPE_CTRL;
  ep->txFifoNum      = 0;
  ep->packetSize     = p->deviceDescriptor->bMaxPacketSize0;

  if ( ep->packetSize == 32 )
  {
    dev->ep0MpsCode = _USB_DOEP0CTL_MPS_32B;
  }
  else if ( ep->packetSize == 64 )
  {
    dev->ep0MpsCode = _USB_DOEP0CTL_MPS_64B;
  }
  else
  {
    return USB_STATUS_ILLEGAL;
  }

  ep->remaining      = 0;
  ep->xferred        = 0;
  ep->state          = D_EP_IDLE;
  ep->xferCompleteCb = NULL;
  ep->fifoSize       = ep->packetSize / 4;

  totalTxFifoSize = ep->fifoSize * p->bufferingMultiplier[ 0 ];
  totalRxFifoSize = (ep->fifoSize + 1) * p->bufferingMultiplier[ 0 ];

#if defined( DEBUG_USB_API )
  /* Do a sanity check on the configuration descriptor */
  {
    int i;

    /* Check if bLength's adds up exactly to wTotalLength */
    i = 0;
    conf = (uint8_t*)dev->configDescriptor;
    confEnd = conf + dev->configDescriptor->wTotalLength;

    while ( conf < confEnd )
    {
      if ( *conf == 0 )
        break;

      i += *conf;
      conf += *conf;
    }

    if ( ( conf != confEnd                          ) ||
         ( i != dev->configDescriptor->wTotalLength )    )
    {
      DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal configuration descriptor" );
      EFM_ASSERT( false );
      return USB_STATUS_ILLEGAL;
    }
  }
#endif /* defined( DEBUG_USB_API ) */

  /* Parse configuration decriptor */
  numEps = 0;
  numInEps  = 0;
  numOutEps = 0;
  conf = (uint8_t*)dev->configDescriptor;
  confEnd = conf + dev->configDescriptor->wTotalLength;

  txFifoNum = 1;
  while ( conf < confEnd )
  {
    if ( *conf == 0 )
    {
      DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal configuration descriptor" );
      EFM_ASSERT( false );
      return USB_STATUS_ILLEGAL;
    }

    if ( *(conf + 1) == USB_ENDPOINT_DESCRIPTOR )
    {
      numEps++;
      epd = (USB_EndpointDescriptor_TypeDef*)conf;

#if defined( __GNUC__ )
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
      ep                 = &dev->ep[ numEps ];
#if defined( __GNUC__ )
#pragma GCC diagnostic pop
#endif

      ep->in             = ( epd->bEndpointAddress & USB_SETUP_DIR_MASK ) != 0;
      ep->buf            = NULL;
      ep->addr           = epd->bEndpointAddress;
      ep->num            = ep->addr & USB_EPNUM_MASK;
      ep->mask           = 1 << ep->num;
      ep->type           = epd->bmAttributes & CONFIG_DESC_BM_TRANSFERTYPE;
      ep->packetSize     = epd->wMaxPacketSize;
      ep->remaining      = 0;
      ep->xferred        = 0;
      ep->state          = D_EP_IDLE;
      ep->xferCompleteCb = NULL;

      if ( p->bufferingMultiplier[ numEps ] == 0 )
      {
        DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal EP fifo buffer configuration" );
        EFM_ASSERT( false );
        return USB_STATUS_ILLEGAL;
      }

      if ( ep->in )
      {
        numInEps++;
        ep->txFifoNum = txFifoNum++;
        ep->fifoSize = ( ( ep->packetSize + 3 ) / 4 )
                       * p->bufferingMultiplier[ numEps ];
        dev->inEpAddr2EpIndex[ ep->num ] = numEps;
        totalTxFifoSize += ep->fifoSize;
        if ( ep->num > MAX_NUM_IN_EPS )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal IN EP address" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      }
      else
      {
        numOutEps++;
        ep->fifoSize = ( ( ( ep->packetSize + 3 ) / 4 ) + 1 )
                       * p->bufferingMultiplier[ numEps ];
        dev->outEpAddr2EpIndex[ ep->num ] = numEps;
        totalRxFifoSize += ep->fifoSize;
        if ( ep->num > MAX_NUM_OUT_EPS )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal OUT EP address" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      }
    }
    else if ( *(conf + 1) == USB_INTERFACE_DESCRIPTOR )
    {
      id = (USB_InterfaceDescriptor_TypeDef*)conf;

      if ( id->bAlternateSetting == 0 )     // Only check default interfaces
      {
        if ( dev->numberOfInterfaces != id->bInterfaceNumber )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal interface number" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      dev->numberOfInterfaces++;
      }
    }

    conf += *conf;
  }

  /* Rx-FIFO size: SETUP packets : 4*n + 6    n=#CTRL EP's
   *               GOTNAK        : 1
   *               Status info   : 2*n        n=#OUT EP's (EP0 included) in HW
   */
  totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );

  if ( dev->configDescriptor->bNumInterfaces != dev->numberOfInterfaces )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal interface count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numEps != NUM_EP_USED )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numInEps > MAX_NUM_IN_EPS )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal IN EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numOutEps > MAX_NUM_OUT_EPS )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal OUT EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  INT_Disable();

  /* Enable USB clock */
  CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC;

#if defined( CMU_OSCENCMD_USHFRCOEN )
  CMU->USHFRCOCONF = CMU_USHFRCOCONF_BAND_48MHZ;
  CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_USHFRCO );

  /* Enable USHFRCO Clock Recovery mode. */
  CMU->USBCRCTRL |= CMU_USBCRCTRL_EN;

  /* Turn on Low Energy Mode (LEM) features. */
  USB->CTRL = USB_CTRL_LEMOSCCTRL_GATE
              | USB_CTRL_LEMIDLEEN
              | USB_CTRL_LEMPHYCTRL;
#else
  CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK );
#endif

  USBHAL_DisableGlobalInt();

  if ( USBDHAL_CoreInit( totalRxFifoSize, totalTxFifoSize ) == USB_STATUS_OK )
  {
    USBDHAL_EnableUsbResetAndSuspendInt();
    USBHAL_EnableGlobalInt();
    NVIC_ClearPendingIRQ( USB_IRQn );
    NVIC_EnableIRQ( USB_IRQn );
  }
  else
  {
    INT_Enable();
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), FIFO setup error" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
  if ( USBHAL_VbusIsOn() )
  {
    USBD_SetUsbState( USBD_STATE_POWERED );
  }
  else
#endif
  {
    USBD_SetUsbState( USBD_STATE_NONE );
  }

  INT_Enable();
  return USB_STATUS_OK;
}