/***************************************************************************//**
 * @file
 * @brief Digital to Analog Converter (VDAC) peripheral API
 *******************************************************************************
 * # License
 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
 *******************************************************************************
 *
 * SPDX-License-Identifier: Zlib
 *
 * The licensor of this software is Silicon Laboratories Inc.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 ******************************************************************************/

#ifndef EM_VDAC_H
#define EM_VDAC_H

#include "em_device.h"

#if defined(VDAC_COUNT) && (VDAC_COUNT > 0)

#include "sl_assert.h"
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/***************************************************************************//**
 * @addtogroup vdac VDAC - Voltage DAC
 * @brief Digital to Analog Voltage Converter (VDAC) Peripheral API
 *
 * @details
 *  This module contains functions to control the VDAC peripheral of Silicon
 *  Labs' 32-bit MCUs and SoCs. VDAC converts digital values to analog
 *  signals at up to 500 ksps with 12-bit accuracy. VDAC is designed for
 *  low energy consumption, but can also provide very good performance.
 *
 *  The following steps are necessary for basic operation:
 *
 *  Clock enable:
 *  @code
    CMU_ClockEnable(cmuClock_VDAC0, true);@endcode
 *
 *  Initialize the VDAC with default settings and modify selected fields:
 *  @code
    VDAC_Init_TypeDef vdacInit          = VDAC_INIT_DEFAULT;
    VDAC_InitChannel_TypeDef vdacChInit = VDAC_INITCHANNEL_DEFAULT;

    // Set prescaler to get 1 MHz VDAC clock frequency.
    vdacInit.prescaler = VDAC_PrescaleCalc(1000000, true, 0); // function call for series 0/1
    VDAC_Init(VDAC0, &vdacInit);

    vdacChInit.enable = true;
    VDAC_InitChannel(VDAC0, &vdacChInit, 0);@endcode
 *
 *  Perform a conversion:
 *  @code
    VDAC_ChannelOutputSet(VDAC0, 0, 250);@endcode
 *
 * @note The output stage of a VDAC channel consists of an on-chip operational
 *   amplifier (OPAMP) in the OPAMP module. This OPAMP is highly configurable;
 *   and to exploit the VDAC functionality fully, configure the OPAMP using
 *   the OPAMP API. Using the OPAMP API also loads OPAMP calibration values.
 *   The default (reset) settings of OPAMP is sufficient for many applications.
 * @{
 ******************************************************************************/

/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */

/** Validation of VDAC register block pointer reference for assert statements.*/

#if VDAC_COUNT == 1
#define VDAC_REF_VALID(ref)   ((ref) == VDAC0)
#elif VDAC_COUNT == 2
#define VDAC_REF_VALID(ref)   (((ref) == VDAC0) || ((ref) == VDAC1))
#else
#error "Undefined number of VDACs."
#endif

/** @endcond */

/*******************************************************************************
 ********************************   ENUMS   ************************************
 ******************************************************************************/

#if !defined(_SILICON_LABS_32B_SERIES_2)
/** Channel refresh period. */
typedef enum {
  vdacRefresh8  = _VDAC_CTRL_REFRESHPERIOD_8CYCLES,  /**< Refresh every 8 clock cycles. */
  vdacRefresh16 = _VDAC_CTRL_REFRESHPERIOD_16CYCLES, /**< Refresh every 16 clock cycles. */
  vdacRefresh32 = _VDAC_CTRL_REFRESHPERIOD_32CYCLES, /**< Refresh every 32 clock cycles. */
  vdacRefresh64 = _VDAC_CTRL_REFRESHPERIOD_64CYCLES, /**< Refresh every 64 clock cycles. */
} VDAC_Refresh_TypeDef;

/** Reference voltage for VDAC. */
typedef enum {
  vdacRef1V25Ln = _VDAC_CTRL_REFSEL_1V25LN, /**< Internal low noise 1.25 V band gap reference. */
  vdacRef2V5Ln  = _VDAC_CTRL_REFSEL_2V5LN,  /**< Internal low noise 2.5 V band gap reference. */
  vdacRef1V25   = _VDAC_CTRL_REFSEL_1V25,   /**< Internal 1.25 V band gap reference. */
  vdacRef2V5    = _VDAC_CTRL_REFSEL_2V5,    /**< Internal 2.5 V band gap reference. */
  vdacRefAvdd   = _VDAC_CTRL_REFSEL_VDD,    /**< AVDD reference. */
  vdacRefExtPin = _VDAC_CTRL_REFSEL_EXT,    /**< External pin reference. */
} VDAC_Ref_TypeDef;

/** Peripheral Reflex System signal used to trigger VDAC channel conversion. */
typedef enum {
  vdacPrsSelCh0 =  _VDAC_CH0CTRL_PRSSEL_PRSCH0,  /**< PRS ch 0 triggers conversion. */
  vdacPrsSelCh1 =  _VDAC_CH0CTRL_PRSSEL_PRSCH1,  /**< PRS ch 1 triggers conversion. */
  vdacPrsSelCh2 =  _VDAC_CH0CTRL_PRSSEL_PRSCH2,  /**< PRS ch 2 triggers conversion. */
  vdacPrsSelCh3 =  _VDAC_CH0CTRL_PRSSEL_PRSCH3,  /**< PRS ch 3 triggers conversion. */
  vdacPrsSelCh4 =  _VDAC_CH0CTRL_PRSSEL_PRSCH4,  /**< PRS ch 4 triggers conversion. */
  vdacPrsSelCh5 =  _VDAC_CH0CTRL_PRSSEL_PRSCH5,  /**< PRS ch 5 triggers conversion. */
  vdacPrsSelCh6 =  _VDAC_CH0CTRL_PRSSEL_PRSCH6,  /**< PRS ch 6 triggers conversion. */
  vdacPrsSelCh7 =  _VDAC_CH0CTRL_PRSSEL_PRSCH7,  /**< PRS ch 7 triggers conversion. */
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH8)
  vdacPrsSelCh8 =  _VDAC_CH0CTRL_PRSSEL_PRSCH8,  /**< PRS ch 8 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH9)
  vdacPrsSelCh9 =  _VDAC_CH0CTRL_PRSSEL_PRSCH9,  /**< PRS ch 9 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH10)
  vdacPrsSelCh10 = _VDAC_CH0CTRL_PRSSEL_PRSCH10, /**< PRS ch 10 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH11)
  vdacPrsSelCh11 = _VDAC_CH0CTRL_PRSSEL_PRSCH11, /**< PRS ch 11 triggers conversion. */
#endif
} VDAC_PrsSel_TypeDef;

/** Channel conversion trigger mode. */
typedef enum {
  vdacTrigModeSw        = _VDAC_CH0CTRL_TRIGMODE_SW,        /**< Channel is triggered by CHnDATA or COMBDATA write. */
  vdacTrigModePrs       = _VDAC_CH0CTRL_TRIGMODE_PRS,       /**< Channel is triggered by PRS input. */
  vdacTrigModeRefresh   = _VDAC_CH0CTRL_TRIGMODE_REFRESH,   /**< Channel is triggered by Refresh timer. */
  vdacTrigModeSwPrs     = _VDAC_CH0CTRL_TRIGMODE_SWPRS,     /**< Channel is triggered by CHnDATA/COMBDATA write or PRS input. */
  vdacTrigModeSwRefresh = _VDAC_CH0CTRL_TRIGMODE_SWREFRESH, /**< Channel is triggered by CHnDATA/COMBDATA write or Refresh timer. */
  vdacTrigModeLesense   = _VDAC_CH0CTRL_TRIGMODE_LESENSE,   /**< Channel is triggered by LESENSE. */
} VDAC_TrigMode_TypeDef;

/*******************************************************************************
 *******************************   STRUCTS   ***********************************
 ******************************************************************************/

/** VDAC initialization structure, common for both channels. */
typedef struct {
  /** Selects between main and alternate output path calibration values. */
  bool                  mainCalibration;

  /** Selects clock from asynchronous or synchronous (with respect to
      peripheral clock) source. */
  bool                  asyncClockMode;

  /** Warm-up mode, keep VDAC on (in idle) - or shutdown between conversions.*/
  bool                  warmupKeepOn;

  /** Channel refresh period. */
  VDAC_Refresh_TypeDef  refresh;

  /** Prescaler for VDAC clock. Clock is source clock divided by prescaler+1. */
  uint32_t              prescaler;

  /** Reference voltage to use. */
  VDAC_Ref_TypeDef      reference;

  /** Enable/disable reset of prescaler on CH 0 start. */
  bool                 ch0ResetPre;

  /** Enable/disable output enable control by CH1 PRS signal. */
  bool                 outEnablePRS;

  /** Enable/disable sine mode. */
  bool                 sineEnable;

  /** Select if single ended or differential output mode. */
  bool                 diff;
} VDAC_Init_TypeDef;

/** Default configuration for VDAC initialization structure. */
#define VDAC_INIT_DEFAULT                                                \
  {                                                                      \
    true,                 /* Use main output path calibration values. */ \
    false,                /* Use synchronous clock mode. */              \
    false,                /* Turn off between sample off conversions.*/  \
    vdacRefresh8,         /* Refresh every 8th cycle. */                 \
    0,                    /* No prescaling. */                           \
    vdacRef1V25Ln,        /* 1.25 V internal low noise reference. */     \
    false,                /* Do not reset prescaler on CH 0 start. */    \
    false,                /* VDAC output enable always on. */            \
    false,                /* Disable sine mode. */                       \
    false                 /* Single ended mode. */                       \
  }

/** VDAC channel initialization structure. */
typedef struct {
  /** Enable channel. */
  bool                  enable;

  /**
   * Peripheral reflex system trigger selection. Only applicable if @p trigMode
   * is set to @p vdacTrigModePrs or @p vdacTrigModeSwPrs. */
  VDAC_PrsSel_TypeDef   prsSel;

  /** Treat the PRS signal asynchronously. */
  bool                  prsAsync;

  /** Channel conversion trigger mode. */
  VDAC_TrigMode_TypeDef trigMode;

  /** Set channel conversion mode to sample/shut-off mode. Default is
   *  continuous.*/
  bool                  sampleOffMode;
} VDAC_InitChannel_TypeDef;

/** Default configuration for VDAC channel initialization structure. */
#define VDAC_INITCHANNEL_DEFAULT                                                \
  {                                                                             \
    false,            /* Leave channel disabled when initialization is done. */ \
    vdacPrsSelCh0,    /* PRS CH 0 triggers conversion. */                       \
    false,            /* Treat PRS channel as a synchronous signal. */          \
    vdacTrigModeSw,   /* Conversion trigged by CH0DATA or COMBDATA write. */    \
    false,            /* Channel conversion set to continuous. */               \
  }
#else // defined(_SILICON_LABS_32B_SERIES_2)

/** Channel refresh period. */
typedef enum {
  vdacRefresh2    = _VDAC_CFG_REFRESHPERIOD_CYCLES2,    /**< Refresh every 2 clock cycles. */
  vdacRefresh4    = _VDAC_CFG_REFRESHPERIOD_CYCLES4,    /**< Refresh every 4 clock cycles. */
  vdacRefresh8    = _VDAC_CFG_REFRESHPERIOD_CYCLES8,    /**< Refresh every 8 clock cycles. */
  vdacRefresh16   = _VDAC_CFG_REFRESHPERIOD_CYCLES16,   /**< Refresh every 16 clock cycles. */
  vdacRefresh32   = _VDAC_CFG_REFRESHPERIOD_CYCLES32,   /**< Refresh every 32 clock cycles. */
  vdacRefresh64   = _VDAC_CFG_REFRESHPERIOD_CYCLES64,   /**< Refresh every 64 clock cycles. */
  vdacRefresh128  = _VDAC_CFG_REFRESHPERIOD_CYCLES128,  /**< Refresh every 128 clock cycles. */
  vdacRefresh256  = _VDAC_CFG_REFRESHPERIOD_CYCLES256,  /**< Refresh every 256 clock cycles. */
} VDAC_Refresh_TypeDef;

/** Timer overflow period. */
typedef enum {
  vdacCycles2  = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES2,    /**< Overflows every 2 clock cycles. */
  vdacCycles4  = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES4,    /**< Overflows every 4 clock cycles. */
  vdacCycles8  = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES8,    /**< Overflows every 8 clock cycles. */
  vdacCycles16 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES16,   /**< Overflows every 16 clock cycles. */
  vdacCycles32 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES32,   /**< Overflows every 32 clock cycles. */
  vdacCycles64 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES64    /**< Overflows every 64 clock cycles. */
} VDAC_TimerOverflow_TypeDef;

/** Reference voltage for VDAC. */
typedef enum {
  vdacRef1V25   = _VDAC_CFG_REFRSEL_V125,   /**< Internal 1.25 V band gap reference. */
  vdacRef2V5    = _VDAC_CFG_REFRSEL_V25,    /**< Internal 2.5 V band gap reference. */
  vdacRefAvdd   = _VDAC_CFG_REFRSEL_VDD,    /**< AVDD reference. */
  vdacRefExtPin = _VDAC_CFG_REFRSEL_EXT,    /**< External pin reference. */
} VDAC_Ref_TypeDef;

/** Refresh source for VDAC. */
typedef enum {
  vdacRefreshSrcNone          = _VDAC_CH0CFG_REFRESHSOURCE_NONE,        /**< No refresh source. */
  vdacRefreshSrcRefreshTimer  = _VDAC_CH0CFG_REFRESHSOURCE_REFRESHTIMER,/**< Refresh triggered by refresh timer overflow. */
  vdacRefreshSrcSyncPrs       = _VDAC_CH0CFG_REFRESHSOURCE_SYNCPRS,     /**< Refresh triggered by sync PRS. */
  vdacRefreshSrcAsyncPrs      = _VDAC_CH0CFG_REFRESHSOURCE_ASYNCPRS,    /**< Refresh triggered by async PRS. */
} VDAC_RefreshSource_TypeDef;

/** Channel conversion trigger mode. */
typedef enum {
  vdacTrigModeNone          = _VDAC_CH0CFG_TRIGMODE_NONE,           /**< No conversion trigger source selected. */
  vdacTrigModeSw            = _VDAC_CH0CFG_TRIGMODE_SW,             /**< Channel is triggered by CHnDATA or COMBDATA write. */
  vdacTrigModeSyncPrs       = _VDAC_CH0CFG_TRIGMODE_SYNCPRS,        /**< Channel is triggered by Sync PRS input. */
#if defined(LESENSE_PRESENT) && defined(_VDAC_CH0CFG_TRIGMODE_LESENSE)
  vdacTrigModeLesense       = _VDAC_CH0CFG_TRIGMODE_LESENSE,        /**< Channel is triggered by LESENSE. */
#endif
  vdacTrigModeInternalTimer = _VDAC_CH0CFG_TRIGMODE_INTERNALTIMER,  /**< Channel is triggered by Internal Timer. */
  vdacTrigModeAsyncPrs      = _VDAC_CH0CFG_TRIGMODE_ASYNCPRS        /**< Channel is triggered by Async PRS input. */
} VDAC_TrigMode_TypeDef;

/** Channel power mode. */
typedef enum {
  vdacPowerModeHighPower    = _VDAC_CH0CFG_POWERMODE_HIGHPOWER,     /**< High power buffer mode. */
  vdacPowerModeLowPower     = _VDAC_CH0CFG_POWERMODE_LOWPOWER       /**< Low power buffer mode. */
} VDAC_PowerMode_TypeDef;

/** VDAC channel Abus port selection. */
typedef enum {
  /** No GPIO selected.  */
  vdacChPortNone    = _VDAC_OUTCTRL_ABUSPORTSELCH0_NONE,
  /** Port A selected.  */
  vdacChPortA       = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTA,
  /** Port B selected.  */
  vdacChPortB       = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTB,
  /** Port C selected.  */
  vdacChPortC       = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTC,
  /** Port D selected.  */
  vdacChPortD       = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTD,
} VDAC_ChPortSel_t;

/*******************************************************************************
 *******************************   STRUCTS   ***********************************
 ******************************************************************************/

/** VDAC initialization structure, common for both channels. */
typedef struct {
  /** Number of prescaled CLK_DAC + 1 for the vdac to warmup. */
  uint32_t                    warmupTime;

  /** Halt during debug. */
  bool                        dbgHalt;

  /** Always allow clk_dac. */
  bool                        onDemandClk;

  /** DMA Wakeup. */
  bool                        dmaWakeUp;

  /** Bias keep warm enable. */
  bool                        biasKeepWarm;

  /** Channel refresh period. */
  VDAC_Refresh_TypeDef        refresh;

  /** Internal timer overflow period. */
  VDAC_TimerOverflow_TypeDef  timerOverflow;

  /** Prescaler for VDAC clock. Clock is source clock divided by prescaler+1. */
  uint32_t                    prescaler;

  /** Reference voltage to use. */
  VDAC_Ref_TypeDef            reference;

  /** Enable/disable reset of prescaler on CH 0 start. */
  bool                        ch0ResetPre;

  /** Sine reset mode. */
  bool                        sineReset;

  /** Enable/disable sine mode. */
  bool                        sineEnable;

  /** Select if single ended or differential output mode. */
  bool                        diff;

#if defined(VDAC_CFG_SINEMODEPRS)
  /**  PRS controlled sinemode enable. */
  bool                        sineModePrsEnable;
#endif
#if defined(VDAC_CFG_OUTENPRS)
  /**  PRS controlled channel output enable. */
  bool                        prsOutEnable;
#endif
} VDAC_Init_TypeDef;

#if defined(VDAC_CFG_SINEMODEPRS)
/** Default configuration for VDAC initialization structure. */
#define VDAC_INIT_DEFAULT                                                                            \
  {                                                                                                  \
    _VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */              \
    false,                        /* Continue while debugging. */                                    \
    false,                        /* On demand clock. */                                             \
    false,                        /* DMA wake up. */                                                 \
    false,                        /* Bias keep warm. */                                              \
    vdacRefresh2,                 /* Refresh every 2th cycle. */                                     \
    vdacCycles2,                  /* Internal overflow every 2th cycle. */                           \
    0,                            /* No prescaling. */                                               \
    vdacRef1V25,                  /* 1.25 V internal low noise reference. */                         \
    false,                        /* Do not reset prescaler on CH 0 start. */                        \
    false,                        /* Sine wave is stopped at the sample its currently outputting. */ \
    false,                        /* Disable sine mode. */                                           \
    false,                        /* Differential mode. */                                           \
    false,                        /* PRS controlled sinemode. */                                     \
    false,                        /* PRS controlled output enable. */                                \
  }
#else
/** Default configuration for VDAC initialization structure. */
#define VDAC_INIT_DEFAULT                                                                            \
  {                                                                                                  \
    _VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */              \
    false,                        /* Continue while debugging. */                                    \
    false,                        /* On demand clock. */                                             \
    false,                        /* DMA wake up. */                                                 \
    false,                        /* Bias keep warm. */                                              \
    vdacRefresh2,                 /* Refresh every 2th cycle. */                                     \
    vdacCycles2,                  /* Internal overflow every 2th cycle. */                           \
    0,                            /* No prescaling. */                                               \
    vdacRef1V25,                  /* 1.25 V internal low noise reference. */                         \
    false,                        /* Do not reset prescaler on CH 0 start. */                        \
    false,                        /* Sine wave is stopped at the sample its currently outputting. */ \
    false,                        /* Disable sine mode. */                                           \
    false,                        /* Differential mode. */                                           \
  }
#endif

#if defined(VDAC_CFG_SINEMODEPRS)
/** Sine mode configuration for VDAC initialization structure. */
#define VDAC_INIT_SINE_GENERATION_MODE                                                               \
  {                                                                                                  \
    _VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */              \
    false,                        /* Continue while debugging. */                                    \
    true,                         /* On demand clock. */                                             \
    false,                        /* DMA wake up. */                                                 \
    false,                        /* Bias keep warm. */                                              \
    vdacRefresh8,                 /* Refresh every 8th cycle. */                                     \
    vdacCycles2,                  /* Internal overflow every 8th cycle. */                           \
    0,                            /* No prescaling. */                                               \
    vdacRef1V25,                  /* 1.25 V internal low noise reference. */                         \
    false,                        /* Do not reset prescaler on CH 0 start. */                        \
    false,                        /* Sine wave is stopped at the sample its currently outputting. */ \
    true,                         /* Enable sine mode. */                                            \
    false,                        /* Differential mode. */                                           \
    false,                        /* PRS controlled sinemode. */                                     \
    false,                        /* PRS controlled output enable. */                                \
  }
#else
/** Sine mode configuration for VDAC initialization structure. */
#define VDAC_INIT_SINE_GENERATION_MODE                                                               \
  {                                                                                                  \
    _VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */              \
    false,                        /* Continue while debugging. */                                    \
    true,                         /* On demand clock. */                                             \
    false,                        /* DMA wake up. */                                                 \
    false,                        /* Bias keep warm. */                                              \
    vdacRefresh8,                 /* Refresh every 8th cycle. */                                     \
    vdacCycles2,                  /* Internal overflow every 8th cycle. */                           \
    0,                            /* No prescaling. */                                               \
    vdacRef1V25,                  /* 1.25 V internal low noise reference. */                         \
    false,                        /* Do not reset prescaler on CH 0 start. */                        \
    false,                        /* Sine wave is stopped at the sample its currently outputting. */ \
    true,                         /* Enable sine mode. */                                            \
    false,                        /* Differential mode. */                                           \
  }
#endif

/** VDAC channel initialization structure. */
typedef struct {
  /** Enable channel. */
  bool                        enable;

  /** Warm-up mode, keep VDAC on (in idle) - or shutdown between conversions.*/
  bool                        warmupKeepOn;

  /** Select high capacitance load mode in conjunction with high power. */
  bool                        highCapLoadEnable;

  /** Channel x FIFO Low threshold data valid level. */
  uint32_t                    fifoLowDataThreshold;

  /** Channel refresh source. */
  VDAC_RefreshSource_TypeDef  chRefreshSource;

  /** Channel conversion trigger mode. */
  VDAC_TrigMode_TypeDef       trigMode;

  /** Channel power mode. */
  VDAC_PowerMode_TypeDef      powerMode;

  /** Set channel conversion mode to sample/shut-off mode. Default is
   *  continuous.*/
  bool                        sampleOffMode;

  /** Vdac channel output pin. */
  uint32_t                    pin;

  /** Vdac channel output port. */
  VDAC_ChPortSel_t            port;

  /** Short High power and low power output. */
  bool                        shortOutput;

  /**  Alternative output enable. */
  bool                        auxOutEnable;

  /**  Main output enable. */
  bool                        mainOutEnable;

  /**  Channel output hold time. */
  uint32_t                    holdOutTime;
} VDAC_InitChannel_TypeDef;

/** Default configuration for VDAC channel initialization structure. */
#define VDAC_INITCHANNEL_DEFAULT                                                      \
  {                                                                                   \
    false,                  /* Leave channel disabled when initialization is done. */ \
    false,                  /* Turn off between sample off conversions.*/             \
    true,                   /* Enable High cap mode. */                               \
    0,                      /* FIFO data low watermark at 0. */                       \
    vdacRefreshSrcNone,     /* Channel refresh source. */                             \
    vdacTrigModeSw,         /* Conversion trigged by CH0DATA or COMBDATA write. */    \
    vdacPowerModeHighPower, /* High power mode enabled. */                            \
    false,                  /* Continuous conversion mode. */                         \
    0,                      /* ABUS pin selected. */                                  \
    vdacChPortNone,         /* No Analog bus port selected. */                        \
    false,                  /* Output not shorted */                                  \
    false,                  /* Alternative output disabled. */                        \
    true,                   /* Main output enabled. */                                \
    0,                      /* Hold out time. Previously called settle time */        \
  }

#endif
/*******************************************************************************
 *****************************   PROTOTYPES   **********************************
 ******************************************************************************/

void VDAC_ChannelOutputSet(VDAC_TypeDef *vdac,
                           unsigned int channel,
                           uint32_t     value);
void VDAC_Enable(VDAC_TypeDef *vdac, unsigned int ch, bool enable);
void VDAC_Init(VDAC_TypeDef *vdac, const VDAC_Init_TypeDef *init);
void VDAC_InitChannel(VDAC_TypeDef *vdac,
                      const VDAC_InitChannel_TypeDef *init,
                      unsigned int ch);

#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
 * @brief
 *  Start/stop Sinemode.
 *
 * @details
 *   This function sends the sine mode start/stop signal to the DAC.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @param[in] start
 *   True to start the Sine mode, false to stop it.
 ******************************************************************************/
__STATIC_INLINE void VDAC_SineModeStart(VDAC_TypeDef *vdac, bool start)
{
  EFM_ASSERT(VDAC_REF_VALID(vdac));

  while (0UL != (vdac->STATUS & VDAC_STATUS_SYNCBUSY)) {
  }

  if (start) {
    vdac->CMD = VDAC_CMD_SINEMODESTART;
    while (0UL == (vdac->STATUS & VDAC_STATUS_SINEACTIVE)) {
    }
  } else {
    vdac->CMD = VDAC_CMD_SINEMODESTOP;
    while (0UL != (vdac->STATUS & VDAC_STATUS_SINEACTIVE)) {
    }
  }
}
#endif

/***************************************************************************//**
 * @brief
 *   Set the output signal of VDAC channel 0 to a given value.
 *
 * @details
 *   This function sets the output signal of VDAC channel 0 by writing @p value
 *   to the CH0DATA register.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @param[in] value
 *   Value to write to channel 0 output register CH0DATA.
 ******************************************************************************/
__STATIC_INLINE void VDAC_Channel0OutputSet(VDAC_TypeDef *vdac,
                                            uint32_t value)
{
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
  EFM_ASSERT(value <= _VDAC_CH0DATA_MASK);
  vdac->CH0DATA = value;
#elif defined(_SILICON_LABS_32B_SERIES_2)
  EFM_ASSERT(value <= _VDAC_CH0F_MASK);
  vdac->CH0F = value;
#endif
}

/***************************************************************************//**
 * @brief
 *   Set the output signal of VDAC channel 1 to a given value.
 *
 * @details
 *   This function sets the output signal of VDAC channel 1 by writing @p value
 *   to the CH1DATA register.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @param[in] value
 *   Value to write to channel 1 output register CH1DATA.
 ******************************************************************************/
__STATIC_INLINE void VDAC_Channel1OutputSet(VDAC_TypeDef *vdac,
                                            uint32_t value)
{
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
  EFM_ASSERT(value <= _VDAC_CH1DATA_MASK);
  vdac->CH1DATA = value;
#elif defined(_SILICON_LABS_32B_SERIES_2)
  EFM_ASSERT(value <= _VDAC_CH1F_MASK);
  vdac->CH1F = value;
#endif
}

/***************************************************************************//**
 * @brief
 *   Clear one or more pending VDAC interrupts.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @param[in] flags
 *   Pending VDAC interrupt source to clear. Use a bitwise logic OR combination
 *   of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void VDAC_IntClear(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
  vdac->IF_CLR = flags;
#else
  vdac->IFC = flags;
#endif
}

/***************************************************************************//**
 * @brief
 *   Disable one or more VDAC interrupts.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @param[in] flags
 *   VDAC interrupt sources to disable. Use a bitwise logic OR combination of
 *   valid interrupt flags for the VDAC module (VDAC_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void VDAC_IntDisable(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
  vdac->IEN_CLR = flags;
#else
  vdac->IEN &= ~flags;
#endif
}

/***************************************************************************//**
 * @brief
 *   Enable one or more VDAC interrupts.
 *
 * @note
 *   Depending on the use, a pending interrupt may already be set prior to
 *   enabling the interrupt. To ignore a pending interrupt, consider using
 *   VDAC_IntClear() prior to enabling the interrupt.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @param[in] flags
 *   VDAC interrupt sources to enable. Use a bitwise logic OR combination
 *   of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void VDAC_IntEnable(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
  vdac->IEN_SET = flags;
#else
  vdac->IEN |= flags;
#endif
}

/***************************************************************************//**
 * @brief
 *   Get pending VDAC interrupt flags.
 *
 * @note
 *   The event bits are not cleared by the use of this function.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @return
 *   VDAC interrupt sources pending. Use a bitwise logic OR combination
 *   of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE uint32_t VDAC_IntGet(VDAC_TypeDef *vdac)
{
  return vdac->IF;
}

/***************************************************************************//**
 * @brief
 *   Get enabled and pending VDAC interrupt flags.
 *   Useful for handling more interrupt sources in the same interrupt handler.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @note
 *   Interrupt flags are not cleared by the use of this function.
 *
 * @return
 *   Pending and enabled VDAC interrupt sources.
 *   The return value is the bitwise AND combination of
 *   - the OR combination of enabled interrupt sources in VDACx_IEN_nnn
 *     register (VDACx_IEN_nnn) and
 *   - the OR combination of valid interrupt flags of the VDAC module
 *     (VDACx_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE uint32_t VDAC_IntGetEnabled(VDAC_TypeDef *vdac)
{
  uint32_t ien = vdac->IEN;

  /* Bitwise AND of pending and enabled interrupts */
  return vdac->IF & ien;
}

/***************************************************************************//**
 * @brief
 *   Set one or more pending VDAC interrupts from SW.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @param[in] flags
 *   VDAC interrupt sources to set to pending. Use a bitwise logic OR
 *   combination of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void VDAC_IntSet(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
  vdac->IF_SET = flags;
#else
  vdac->IFS = flags;
#endif
}

#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
 * @brief
 *    Get the VDAC Status register.
 *
 * @param[in] vdac
 *   Pointer to VDAC peripheral register block.
 *
 * @return
 *    Current STATUS register value.
 ******************************************************************************/
__STATIC_INLINE uint32_t VDAC_GetStatus(VDAC_TypeDef *vdac)
{
  return vdac->STATUS;
}
#endif

#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
uint32_t VDAC_PrescaleCalc(uint32_t vdacFreq, bool syncMode, uint32_t hfperFreq);
#else
uint32_t VDAC_PrescaleCalc(VDAC_TypeDef *vdac, uint32_t vdacFreq);
#endif

void VDAC_Reset(VDAC_TypeDef *vdac);

/** @} (end addtogroup vdac) */

#ifdef __cplusplus
}
#endif

#endif /* defined(VDAC_COUNT) && (VDAC_COUNT > 0) */
#endif /* EM_VDAC_H */
