added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Revision:
50:a417edff4437
Parent:
0:9b334a45a8ff
Child:
144:ef7eb2e8f9f7
--- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_adc.c	Wed Jan 13 12:45:11 2016 +0000
+++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_adc.c	Fri Jan 15 07:45:16 2016 +0000
@@ -1,10 +1,10 @@
 /***************************************************************************//**
  * @file em_adc.c
  * @brief Analog to Digital Converter (ADC) Peripheral API
- * @version 3.20.12
+ * @version 4.2.1
  *******************************************************************************
  * @section License
- * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
+ * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
  *******************************************************************************
  *
  * Permission is granted to anyone to use this software for any purpose,
@@ -30,12 +30,12 @@
  *
  ******************************************************************************/
 
-
 #include "em_adc.h"
-#if defined(ADC_COUNT) && (ADC_COUNT > 0)
+#if defined( ADC_COUNT ) && ( ADC_COUNT > 0 )
 
 #include "em_cmu.h"
 #include "em_assert.h"
+#include <stddef.h>
 
 /***************************************************************************//**
  * @addtogroup EM_Library
@@ -58,11 +58,124 @@
 #define ADC_REF_VALID(ref)    ((ref) == ADC0)
 
 /** Max ADC clock */
+#if defined( _SILICON_LABS_32B_PLATFORM_1 )
 #define ADC_MAX_CLOCK    13000000
+#else
+#define ADC_MAX_CLOCK    16000000
+#endif
 
 /** Min ADC clock */
 #define ADC_MIN_CLOCK    32000
 
+/** Helper defines for selecting ADC calibration and DEVINFO register fields. */
+#if defined( _DEVINFO_ADC0CAL0_1V25_GAIN_MASK )
+#define DEVINFO_ADC0_GAIN1V25_MASK _DEVINFO_ADC0CAL0_1V25_GAIN_MASK
+#elif defined( _DEVINFO_ADC0CAL0_GAIN1V25_MASK )
+#define DEVINFO_ADC0_GAIN1V25_MASK _DEVINFO_ADC0CAL0_GAIN1V25_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT )
+#define DEVINFO_ADC0_GAIN1V25_SHIFT _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT
+#elif defined( _DEVINFO_ADC0CAL0_GAIN1V25_SHIFT )
+#define DEVINFO_ADC0_GAIN1V25_SHIFT _DEVINFO_ADC0CAL0_GAIN1V25_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK )
+#define DEVINFO_ADC0_OFFSET1V25_MASK _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK
+#elif defined( _DEVINFO_ADC0CAL0_OFFSET1V25_MASK )
+#define DEVINFO_ADC0_OFFSET1V25_MASK _DEVINFO_ADC0CAL0_OFFSET1V25_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT )
+#define DEVINFO_ADC0_OFFSET1V25_SHIFT _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT
+#elif defined( _DEVINFO_ADC0CAL0_OFFSET1V25_SHIFT )
+#define DEVINFO_ADC0_OFFSET1V25_SHIFT _DEVINFO_ADC0CAL0_OFFSET1V25_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL0_2V5_GAIN_MASK )
+#define DEVINFO_ADC0_GAIN2V5_MASK _DEVINFO_ADC0CAL0_2V5_GAIN_MASK
+#elif defined( _DEVINFO_ADC0CAL0_GAIN2V5_MASK )
+#define DEVINFO_ADC0_GAIN2V5_MASK _DEVINFO_ADC0CAL0_GAIN2V5_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT )
+#define DEVINFO_ADC0_GAIN2V5_SHIFT _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT
+#elif defined( _DEVINFO_ADC0CAL0_GAIN2V5_SHIFT )
+#define DEVINFO_ADC0_GAIN2V5_SHIFT _DEVINFO_ADC0CAL0_GAIN2V5_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK )
+#define DEVINFO_ADC0_OFFSET2V5_MASK _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK
+#elif defined( _DEVINFO_ADC0CAL0_OFFSET2V5_MASK )
+#define DEVINFO_ADC0_OFFSET2V5_MASK _DEVINFO_ADC0CAL0_OFFSET2V5_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT )
+#define DEVINFO_ADC0_OFFSET2V5_SHIFT _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT
+#elif defined( _DEVINFO_ADC0CAL0_OFFSET2V5_SHIFT )
+#define DEVINFO_ADC0_OFFSET2V5_SHIFT _DEVINFO_ADC0CAL0_OFFSET2V5_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_VDD_GAIN_MASK )
+#define DEVINFO_ADC0_GAINVDD_MASK _DEVINFO_ADC0CAL1_VDD_GAIN_MASK
+#elif defined( _DEVINFO_ADC0CAL1_GAINVDD_MASK )
+#define DEVINFO_ADC0_GAINVDD_MASK _DEVINFO_ADC0CAL1_GAINVDD_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT )
+#define DEVINFO_ADC0_GAINVDD_SHIFT _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT
+#elif defined( _DEVINFO_ADC0CAL1_GAINVDD_SHIFT )
+#define DEVINFO_ADC0_GAINVDD_SHIFT _DEVINFO_ADC0CAL1_GAINVDD_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK )
+#define DEVINFO_ADC0_OFFSETVDD_MASK _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK
+#elif defined( _DEVINFO_ADC0CAL1_OFFSETVDD_MASK )
+#define DEVINFO_ADC0_OFFSETVDD_MASK _DEVINFO_ADC0CAL1_OFFSETVDD_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT )
+#define DEVINFO_ADC0_OFFSETVDD_SHIFT _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT
+#elif defined( _DEVINFO_ADC0CAL1_OFFSETVDD_SHIFT )
+#define DEVINFO_ADC0_OFFSETVDD_SHIFT _DEVINFO_ADC0CAL1_OFFSETVDD_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK )
+#define DEVINFO_ADC0_GAIN5VDIFF_MASK _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK
+#elif defined( _DEVINFO_ADC0CAL1_GAIN5VDIFF_MASK )
+#define DEVINFO_ADC0_GAIN5VDIFF_MASK _DEVINFO_ADC0CAL1_GAIN5VDIFF_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT )
+#define DEVINFO_ADC0_GAIN5VDIFF_SHIFT _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT
+#elif defined( _DEVINFO_ADC0CAL1_GAIN5VDIFF_SHIFT )
+#define DEVINFO_ADC0_GAIN5VDIFF_SHIFT _DEVINFO_ADC0CAL1_GAIN5VDIFF_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK )
+#define DEVINFO_ADC0_OFFSET5VDIFF_MASK _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK
+#elif defined( _DEVINFO_ADC0CAL1_OFFSET5VDIFF_MASK )
+#define DEVINFO_ADC0_OFFSET5VDIFF_MASK _DEVINFO_ADC0CAL1_OFFSET5VDIFF_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT )
+#define DEVINFO_ADC0_OFFSET5VDIFF_SHIFT _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT
+#elif defined( _DEVINFO_ADC0CAL1_OFFSET5VDIFF_SHIFT )
+#define DEVINFO_ADC0_OFFSET5VDIFF_SHIFT _DEVINFO_ADC0CAL1_OFFSET5VDIFF_SHIFT
+#endif
+
+#if defined( _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK )
+#define DEVINFO_ADC0_OFFSET2XVDD_MASK _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK
+#elif defined( _DEVINFO_ADC0CAL2_OFFSET2XVDD_MASK )
+#define DEVINFO_ADC0_OFFSET2XVDD_MASK _DEVINFO_ADC0CAL2_OFFSET2XVDD_MASK
+#endif
+
+#if defined( _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT )
+#define DEVINFO_ADC0_OFFSET2XVDD_SHIFT _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT
+#elif defined( _DEVINFO_ADC0CAL2_OFFSET2XVDD_SHIFT )
+#define DEVINFO_ADC0_OFFSET2XVDD_SHIFT _DEVINFO_ADC0CAL2_OFFSET2XVDD_SHIFT
+#endif
+
 /** @endcond */
 
 
@@ -74,14 +187,13 @@
 
 /***************************************************************************//**
  * @brief
- *   Load SCAN calibrate register with predefined values for a certain
- *   reference.
+ *   Load ADC calibration register for a selected reference and conversion mode.
  *
  * @details
- *   During production, calibration values are made and stored in the device
- *   information page for known references. Notice that for external references,
+ *   During production, calibration values are stored in the device
+ *   information page for internal references. Notice that for external references,
  *   calibration values must be determined explicitly, and this function
- *   will not modify the calibration register.
+ *   will not modify the calibration register for external references.
  *
  * @param[in] adc
  *   Pointer to ADC peripheral register block.
@@ -89,143 +201,135 @@
  * @param[in] ref
  *   Reference to load calibrated values for. No values are loaded for
  *   external references.
+ *
+ * @param[in] setScanCal
+ *   Select scan mode (true) or single mode (false) calibration load.
  ******************************************************************************/
-static void ADC_CalibrateLoadScan(ADC_TypeDef *adc, ADC_Ref_TypeDef ref)
+static void ADC_LoadDevinfoCal(ADC_TypeDef *adc,
+                               ADC_Ref_TypeDef ref,
+                               bool setScanCal)
 {
-  uint32_t cal;
+  uint32_t calReg;
+  uint32_t newCal;
+  uint32_t mask;
+  uint32_t shift;
 
-  /* Load proper calibration data depending on selected reference */
-  /* NOTE: We use ...SCAN... defines below, they are the same as */
-  /* similar ...SINGLE... defines. */
+  if (setScanCal)
+  {
+    shift = _ADC_CAL_SCANOFFSET_SHIFT;
+    mask  = ~(_ADC_CAL_SCANOFFSET_MASK
+#if defined( _ADC_CAL_SCANOFFSETINV_MASK )
+              | _ADC_CAL_SCANOFFSETINV_MASK
+#endif
+              | _ADC_CAL_SCANGAIN_MASK);
+  }
+  else
+  {
+    shift = _ADC_CAL_SINGLEOFFSET_SHIFT;
+    mask  = ~(_ADC_CAL_SINGLEOFFSET_MASK
+#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK )
+              | _ADC_CAL_SINGLEOFFSETINV_MASK
+#endif
+              | _ADC_CAL_SINGLEGAIN_MASK);
+  }
+
+  calReg = adc->CAL & mask;
+  newCal = 0;
+
   switch (ref)
   {
-  case adcRef1V25:
-    cal  = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
-
-  case adcRef2V5:
-    cal  = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
+    case adcRef1V25:
+      newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_GAIN1V25_MASK)
+                 >> DEVINFO_ADC0_GAIN1V25_SHIFT)
+                << _ADC_CAL_SINGLEGAIN_SHIFT;
+      newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_OFFSET1V25_MASK)
+                 >> DEVINFO_ADC0_OFFSET1V25_SHIFT)
+                << _ADC_CAL_SINGLEOFFSET_SHIFT;
+#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK )
+      newCal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_NEGSEOFFSET1V25_MASK)
+                 >> _DEVINFO_ADC0CAL0_NEGSEOFFSET1V25_SHIFT)
+                << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
+#endif
+      break;
 
-  case adcRefVDD:
-    cal  = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
+    case adcRef2V5:
+      newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_GAIN2V5_MASK)
+                 >> DEVINFO_ADC0_GAIN2V5_SHIFT)
+                << _ADC_CAL_SINGLEGAIN_SHIFT;
+      newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_OFFSET2V5_MASK)
+                 >> DEVINFO_ADC0_OFFSET2V5_SHIFT)
+                << _ADC_CAL_SINGLEOFFSET_SHIFT;
+#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK )
+      newCal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_NEGSEOFFSET2V5_MASK)
+                 >> _DEVINFO_ADC0CAL0_NEGSEOFFSET2V5_SHIFT)
+                << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
+#endif
+      break;
 
-  case adcRef5VDIFF:
-    cal  = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
-
-  case adcRef2xVDD:
-    /* Gain value not of relevance for this reference, leave as is */
-    cal  = adc->CAL & ~_ADC_CAL_SCANOFFSET_MASK;
-    cal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
-
-  /* For external references, the calibration must be determined for the */
-  /* specific application and set explicitly. */
-  default:
-    break;
-  }
-}
+    case adcRefVDD:
+      newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_GAINVDD_MASK)
+                 >> DEVINFO_ADC0_GAINVDD_SHIFT)
+                << _ADC_CAL_SINGLEGAIN_SHIFT;
+      newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_OFFSETVDD_MASK)
+                 >> DEVINFO_ADC0_OFFSETVDD_SHIFT)
+                 << _ADC_CAL_SINGLEOFFSET_SHIFT;
+#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK )
+      newCal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_MASK)
+                 >> _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_SHIFT)
+                << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
+#endif
+      break;
 
-/***************************************************************************//**
- * @brief
- *   Load SINGLE calibrate register with predefined values for a certain
- *   reference.
- *
- * @details
- *   During production, calibration values are made and stored in the device
- *   information page for known references. Notice that for external references,
- *   calibration values must be determined explicitly, and this function
- *   will not modify the calibration register.
- *
- * @param[in] adc
- *   Pointer to ADC peripheral register block.
- *
- * @param[in] ref
- *   Reference to load calibrated values for. No values are loaded for
- *   external references.
- ******************************************************************************/
-static void ADC_CalibrateLoadSingle(ADC_TypeDef *adc, ADC_Ref_TypeDef ref)
-{
-  uint32_t cal;
-
-  /* Load proper calibration data depending on selected reference */
-  /* NOTE: We use ...SCAN... defines below, they are the same as */
-  /* similar ...SINGLE... defines. */
-  switch (ref)
-  {
-  case adcRef1V25:
-    cal  = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
+    case adcRef5VDIFF:
+      newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_GAIN5VDIFF_MASK)
+                 >> DEVINFO_ADC0_GAIN5VDIFF_SHIFT)
+                << _ADC_CAL_SINGLEGAIN_SHIFT;
+      newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_OFFSET5VDIFF_MASK)
+                 >> DEVINFO_ADC0_OFFSET5VDIFF_SHIFT)
+                << _ADC_CAL_SINGLEOFFSET_SHIFT;
+#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK )
+      newCal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_NEGSEOFFSET5VDIFF_MASK)
+                 >> _DEVINFO_ADC0CAL1_NEGSEOFFSET5VDIFF_SHIFT)
+                << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
+#endif
+      break;
 
-  case adcRef2V5:
-    cal  = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
-
-  case adcRefVDD:
-    cal  = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
+    case adcRef2xVDD:
+      /* There is no gain calibration for this reference */
+      newCal |= ((DEVINFO->ADC0CAL2 & DEVINFO_ADC0_OFFSET2XVDD_MASK)
+                 >> DEVINFO_ADC0_OFFSET2XVDD_SHIFT)
+                << _ADC_CAL_SINGLEOFFSET_SHIFT;
+#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK )
+      newCal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_NEGSEOFFSET2XVDD_MASK)
+                 >> _DEVINFO_ADC0CAL2_NEGSEOFFSET2XVDD_SHIFT)
+                << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
+#endif
+      break;
 
-  case adcRef5VDIFF:
-    cal  = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK) >>
-            _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
-    cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
+#if defined( _ADC_SINGLECTRLX_VREFSEL_VDDXWATT )
+    case adcRefVddxAtt:
+      newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_GAINVDD_MASK)
+                 >> DEVINFO_ADC0_GAINVDD_SHIFT)
+                << _ADC_CAL_SINGLEGAIN_SHIFT;
+      newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_OFFSETVDD_MASK)
+                 >> DEVINFO_ADC0_OFFSETVDD_SHIFT)
+                << _ADC_CAL_SINGLEOFFSET_SHIFT;
+      newCal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_MASK)
+                 >> _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_SHIFT)
+                << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
+      break;
+#endif
 
-  case adcRef2xVDD:
-    /* Gain value not of relevance for this reference, leave as is */
-    cal  = adc->CAL & ~_ADC_CAL_SINGLEOFFSET_MASK;
-    cal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK) >>
-            _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
-    adc->CAL = cal;
-    break;
+    /* For external references, the calibration must be determined for the
+       specific application and set by the user. Calibration data is also not
+       available for the internal references adcRefVBGR, adcRefVEntropy and
+       adcRefVBGRlow. */
+    default:
+      newCal = 0;
+      break;
+  }
 
-  /* For external references, the calibration must be determined for the */
-  /* specific application and set explicitly. */
-  default:
-    break;
-  }
+  adc->CAL = calReg | (newCal << shift);
 }
 
 /** @endcond */
@@ -243,6 +347,10 @@
  *   In addition, single and/or scan control configuration must be done, please
  *   refer to ADC_InitSingle() and ADC_InitScan() respectively.
  *
+ *   On ADC architectures with the ADCn->SCANCHCONF register,
+ *   ADC_ScanSingleEndedInit() and ADC_ScanDifferentialInit() can be used to
+ *   assist scan conversion input setup.
+ *
  * @note
  *   This function will stop any ongoing conversion.
  *
@@ -261,23 +369,295 @@
   /* Make sure conversion is not in progress */
   adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
 
-  tmp = ((uint32_t)(init->ovsRateSel) << _ADC_CTRL_OVSRSEL_SHIFT) |
-        (((uint32_t)(init->timebase) << _ADC_CTRL_TIMEBASE_SHIFT) & _ADC_CTRL_TIMEBASE_MASK) |
-        (((uint32_t)(init->prescale) << _ADC_CTRL_PRESC_SHIFT) & _ADC_CTRL_PRESC_MASK) |
-        ((uint32_t)(init->lpfMode) << _ADC_CTRL_LPFMODE_SHIFT) |
-        ((uint32_t)(init->warmUpMode) << _ADC_CTRL_WARMUPMODE_SHIFT);
+  tmp = ((uint32_t)(init->ovsRateSel) << _ADC_CTRL_OVSRSEL_SHIFT)
+        | (((uint32_t)(init->timebase) << _ADC_CTRL_TIMEBASE_SHIFT)
+          & _ADC_CTRL_TIMEBASE_MASK)
+        | (((uint32_t)(init->prescale) << _ADC_CTRL_PRESC_SHIFT)
+          & _ADC_CTRL_PRESC_MASK)
+#if defined ( _ADC_CTRL_LPFMODE_MASK )
+        | ((uint32_t)(init->lpfMode) << _ADC_CTRL_LPFMODE_SHIFT)
+#endif
+        | ((uint32_t)(init->warmUpMode) << _ADC_CTRL_WARMUPMODE_SHIFT);
 
   if (init->tailgate)
   {
     tmp |= ADC_CTRL_TAILGATE;
   }
+  adc->CTRL = tmp;
 
-  adc->CTRL = tmp;
+  /* Set ADC EM2 clock configuration */
+#if defined( _ADC_CTRL_ADCCLKMODE_MASK )
+  BUS_RegMaskedWrite(&ADC0->CTRL,
+                     _ADC_CTRL_ADCCLKMODE_MASK | _ADC_CTRL_ASYNCCLKEN_MASK,
+                     init->em2ClockConfig << _ADC_CTRL_ASYNCCLKEN_SHIFT);
+#endif
+
+#if defined( _SILICON_LABS_32B_PLATFORM_2 )
+  /* Fix for errata ADC_EXXX */
+  ADC_IntClear(adc, ADC_IFC_SCANUF);
+#endif
+}
+
+
+#if defined( _ADC_SCANINPUTSEL_MASK )
+/***************************************************************************//**
+ * @brief
+ *   Clear ADC scan input configuration.
+ *
+ * @param[in] scanInit
+ *   Struct to hold the scan configuration, input configuration.
+ ******************************************************************************/
+void ADC_ScanInputClear(ADC_InitScan_TypeDef *scanInit)
+{
+  /* Clear input configuration */
+
+  /* Select none */
+  scanInit->scanInputConfig.scanInputSel = 0xFFFFFFFF;
+  scanInit->scanInputConfig.scanInputEn = 0;
+
+  /* Default alternative negative inputs */
+  scanInit->scanInputConfig.scanNegSel = _ADC_SCANNEGSEL_RESETVALUE;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ *   Initialize ADC scan single-ended input configuration.
+ *
+ * @details
+ *   Set configuration for ADC scan conversion with single-ended inputs. The
+ *   ADC_InitScan_TypeDef struct updated from this function should be passed to
+ *   ADC_InitScan().
+ *
+ * @param[in] inputGroup
+ *   ADC scan input group. See section 25.3.4 in the reference manual for
+ *   more information.
+ *
+ * @param[in] singleEndedSel
+ *   APORT select.
+ *
+ * @return
+ *   Scan ID of selected ADC input. ee section 25.3.4 in the reference manual for
+ *   more information. Note that the returned integer represents the bit position
+ *   in ADCn_SCANMASK set by this function. The accumulated mask is stored in
+ *   scanInit->scanInputConfig->scanInputEn.
+ ******************************************************************************/
+uint32_t ADC_ScanSingleEndedInputAdd(ADC_InitScan_TypeDef *scanInit,
+                                     ADC_ScanInputGroup_TypeDef inputGroup,
+                                     ADC_PosSel_TypeDef singleEndedSel)
+{
+  uint32_t currentSel;
+  uint32_t newSel;
+  uint32_t scanId;
+
+  scanInit->diff = false;
+
+  /* Check for unsupported APORTs */
+  EFM_ASSERT((singleEndedSel <= adcPosSelAPORT0YCH0) || (singleEndedSel >= adcPosSelAPORT0YCH15));
+
+  /* Decode the input group select by shifting right by 3 */
+  newSel = singleEndedSel >> 3;
+
+  currentSel = (scanInit->scanInputConfig.scanInputSel >> (inputGroup * 8)) & 0xFF;
+
+  /* If none selected */
+  if (currentSel == 0xFF)
+  {
+    scanInit->scanInputConfig.scanInputSel &= ~(0xFF << (inputGroup * 8));
+    scanInit->scanInputConfig.scanInputSel |= (newSel << (inputGroup * 8));
+  }
+  else if (currentSel == newSel)
+  {
+    /* Ok, but do nothing.  */
+  }
+  else
+  {
+    /* Invalid channel range. A range is already selected for this group. */
+    EFM_ASSERT(false);
+  }
+
+  /* Update and return scan input enable mask (SCANMASK) */
+  scanId = (inputGroup * 8) + (singleEndedSel & 0x7);
+  EFM_ASSERT(scanId < 32);
+  scanInit->scanInputConfig.scanInputEn |= 0x1 << scanId;
+  return scanId;
 }
 
 
 /***************************************************************************//**
  * @brief
+ *   Initialize ADC scan differential input configuration.
+ *
+ * @details
+ *   Set configuration for ADC scan conversion with differential inputs. The
+ *   ADC_InitScan_TypeDef struct updated by this function should be passed to
+ *   ADC_InitScan().
+ *
+ * @param[in] scanInit
+ *   Struct to hold the scan and input configuration.
+ *
+ * @param[in] inputGroup
+ *   ADC scan input group. See section 25.3.4 in the reference manual for
+ *   more information.
+ *
+ * @param[in] posSel
+ *   APORT bus pair select. The negative terminal is implicitly selected by
+ *   the positive terminal.
+ *
+ * @param[in] negInput
+ *   ADC scan alternative negative input. Set to adcScanNegInputDefault to select
+ *   default negative input (implicit from posSel).
+ *
+ * @return
+ *   Scan ID of selected ADC input. ee section 25.3.4 in the reference manual for
+ *   more information. Note that the returned integer represents the bit position
+ *   in ADCn_SCANMASK set by this function. The accumulated mask is stored in
+ *   scanInit->scanInputConfig->scanInputEn.
+ ******************************************************************************/
+uint32_t ADC_ScanDifferentialInputAdd(ADC_InitScan_TypeDef *scanInit,
+                                      ADC_ScanInputGroup_TypeDef inputGroup,
+                                      ADC_PosSel_TypeDef posSel,
+                                      ADC_ScanNegInput_TypeDef negInput)
+{
+  uint32_t negInputRegMask = 0;
+  uint32_t negInputRegShift = 0;
+  uint32_t negInputRegVal = 0;
+  uint32_t scanId = 0;
+
+  /* Do a single ended init, then update for differential scan. */
+  scanId = ADC_ScanSingleEndedInputAdd(scanInit, inputGroup, posSel);
+
+  /* Reset to differential mode */
+  scanInit->diff = true;
+
+  /* Set negative ADC input, unless the default is selected. */
+  if (negInput != adcScanNegInputDefault)
+  {
+    if (scanId == 0)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT0NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT0NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 0);
+    }
+    else if (scanId == 2)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT2NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT2NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 0);
+    }
+    else if (scanId == 4)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT4NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT4NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 0);
+    }
+    else if (scanId == 6)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT6NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT6NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 0);
+    }
+    else if (scanId == 9)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT9NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT9NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 1);
+    }
+    else if (scanId == 11)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT11NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT11NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 1);
+    }
+    else if (scanId == 13)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT13NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT13NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 1);
+    }
+    else if (scanId == 15)
+    {
+      negInputRegMask  = _ADC_SCANNEGSEL_INPUT15NEGSEL_MASK;
+      negInputRegShift = _ADC_SCANNEGSEL_INPUT15NEGSEL_SHIFT;
+      EFM_ASSERT(inputGroup == 1);
+    }
+    else
+    {
+      /* There is not negative input option for this positive input (negInput is posInput + 1). */
+      EFM_ASSERT(false);
+    }
+
+    /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 0, 2, 4 and 6 */
+    if (inputGroup == 0)
+    {
+      switch (negInput)
+      {
+        case adcScanNegInput1:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT1;
+          break;
+
+        case adcScanNegInput3:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT3;
+          break;
+
+        case adcScanNegInput5:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT5;
+          break;
+
+        case adcScanNegInput7:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT7;
+          break;
+
+        default:
+          /* Invalid selection. Options are input 1, 3, 5 and 7. */
+          EFM_ASSERT(false);
+          break;
+      }
+    }
+    else if (inputGroup == 1)
+    {
+      /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 9, 11, 13 and 15 */
+      switch (negInput)
+      {
+        case adcScanNegInput8:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT8;
+          break;
+
+        case adcScanNegInput10:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT10;
+          break;
+
+        case adcScanNegInput12:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT12;
+          break;
+
+        case adcScanNegInput14:
+          negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT14;
+          break;
+
+        default:
+          /* Invalid selection. Options are input 8, 10, 12 and 14. */
+          EFM_ASSERT(false);
+          break;
+      }
+    }
+    else
+    {
+      /* No alternative negative input for input group > 1 */
+      EFM_ASSERT(false);
+    }
+
+    /* Update config */
+    scanInit->scanInputConfig.scanNegSel &= ~negInputRegMask;
+    scanInit->scanInputConfig.scanNegSel |= negInputRegVal << negInputRegShift;
+  }
+  return scanId;
+}
+#endif
+
+
+/***************************************************************************//**
+ * @brief
  *   Initialize ADC scan sequence.
  *
  * @details
@@ -305,14 +685,18 @@
   /* Make sure scan sequence is not in progress */
   adc->CMD = ADC_CMD_SCANSTOP;
 
-  /* Load proper calibration data depending on selected reference */
-  ADC_CalibrateLoadScan(adc, init->reference);
+  /* Load calibration data for selected reference */
+  ADC_LoadDevinfoCal(adc, init->reference, true);
 
-  tmp = ((uint32_t)(init->prsSel) << _ADC_SCANCTRL_PRSSEL_SHIFT) |
-        ((uint32_t)(init->acqTime) << _ADC_SCANCTRL_AT_SHIFT) |
-        ((uint32_t)(init->reference) << _ADC_SCANCTRL_REF_SHIFT) |
-        init->input |
-        ((uint32_t)(init->resolution) << _ADC_SCANCTRL_RES_SHIFT);
+  tmp = 0
+#if defined ( _ADC_SCANCTRL_PRSSEL_MASK )
+        | (init->prsSel << _ADC_SCANCTRL_PRSSEL_SHIFT)
+#endif
+        | (init->acqTime << _ADC_SCANCTRL_AT_SHIFT)
+#if defined ( _ADC_SCANCTRL_INPUTMASK_MASK )
+        | init->input
+#endif
+        | (init->resolution << _ADC_SCANCTRL_RES_SHIFT);
 
   if (init->prsEnable)
   {
@@ -324,17 +708,82 @@
     tmp |= ADC_SCANCTRL_ADJ_LEFT;
   }
 
+#if defined( _ADC_SCANCTRL_INPUTMASK_MASK )
   if (init->diff)
+#elif defined( _ADC_SCANINPUTSEL_MASK )
+  if (init->diff)
+#endif
   {
     tmp |= ADC_SCANCTRL_DIFF;
   }
 
   if (init->rep)
   {
+#if defined( _SILICON_LABS_32B_PLATFORM_2 )
+  /* Scan repeat mode does not work on platform 2 as described in errata  ADC_EXXX. */
+  EFM_ASSERT(false);
+#endif
     tmp |= ADC_SCANCTRL_REP;
   }
 
+  /* Set scan reference. Check if reference configuraion is extended to SCANCTRLX. */
+#if defined ( _ADC_SCANCTRLX_VREFSEL_MASK )
+  if (init->reference & ADC_CTRLX_VREFSEL_REG)
+  {
+    /* Select extension register */
+    tmp |= ADC_SCANCTRL_REF_CONF;
+  }
+  else
+  {
+    tmp |= init->reference << _ADC_SCANCTRL_REF_SHIFT;
+  }
+#else
+  tmp |= init->reference << _ADC_SCANCTRL_REF_SHIFT;
+#endif
+
+#if defined( _ADC_SCANCTRL_INPUTMASK_MASK )
+  tmp |= init->input;
+#endif
+
   adc->SCANCTRL = tmp;
+
+  /* Update SINGLECTRLX for reference select and PRS select */
+#if defined ( _ADC_SCANCTRLX_MASK )
+  tmp = adc->SCANCTRLX & ~(_ADC_SCANCTRLX_VREFSEL_MASK
+                         | _ADC_SCANCTRLX_PRSSEL_MASK
+                         | _ADC_SCANCTRLX_FIFOOFACT_MASK);
+  if (init->reference & ADC_CTRLX_VREFSEL_REG)
+  {
+    tmp |= (init->reference & ~ADC_CTRLX_VREFSEL_REG) << _ADC_SCANCTRLX_VREFSEL_SHIFT;
+  }
+
+  tmp |= init->prsSel << _ADC_SCANCTRLX_PRSSEL_SHIFT;
+
+  if (init->fifoOverwrite)
+  {
+    tmp |= ADC_SCANCTRLX_FIFOOFACT_OVERWRITE;
+  }
+
+  adc->SCANCTRLX = tmp;
+#endif
+
+#if defined( _ADC_CTRL_SCANDMAWU_MASK )
+  BUS_RegBitWrite(&adc->CTRL, _ADC_CTRL_SCANDMAWU_SHIFT, init->scanDmaEm2Wu);
+#endif
+
+  /* Write scan input configuration */
+#if defined( _ADC_SCANINPUTSEL_MASK )
+  adc->SCANINPUTSEL = init->scanInputConfig.scanInputSel;
+  adc->SCANMASK     = init->scanInputConfig.scanInputEn;
+  adc->SCANNEGSEL   = init->scanInputConfig.scanNegSel;
+#endif
+
+  /* Assert for any APORT bus conflicts programming errors */
+#if defined( _ADC_BUSCONFLICT_MASK )
+  tmp = adc->BUSREQ;
+  EFM_ASSERT(!(tmp & adc->BUSCONFLICT));
+  EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK));
+#endif
 }
 
 
@@ -367,14 +816,24 @@
   /* Make sure single conversion is not in progress */
   adc->CMD = ADC_CMD_SINGLESTOP;
 
-  /* Load proper calibration data depending on selected reference */
-  ADC_CalibrateLoadSingle(adc, init->reference);
+  /* Load calibration data for selected reference */
+  ADC_LoadDevinfoCal(adc, init->reference, false);
 
-  tmp = ((uint32_t)(init->prsSel) << _ADC_SINGLECTRL_PRSSEL_SHIFT) |
-        ((uint32_t)(init->acqTime) << _ADC_SINGLECTRL_AT_SHIFT) |
-        ((uint32_t)(init->reference) << _ADC_SINGLECTRL_REF_SHIFT) |
-        ((uint32_t)(init->input) << _ADC_SINGLECTRL_INPUTSEL_SHIFT) |
-        ((uint32_t)(init->resolution) << _ADC_SINGLECTRL_RES_SHIFT);
+  tmp = 0
+#if defined( _ADC_SINGLECTRL_PRSSEL_MASK )
+        | (init->prsSel << _ADC_SINGLECTRL_PRSSEL_SHIFT)
+#endif
+        | (init->acqTime << _ADC_SINGLECTRL_AT_SHIFT)
+#if defined( _ADC_SINGLECTRL_INPUTSEL_MASK )
+        | (init->input << _ADC_SINGLECTRL_INPUTSEL_SHIFT)
+#endif
+#if defined( _ADC_SINGLECTRL_POSSEL_MASK )
+        | (init->posSel << _ADC_SINGLECTRL_POSSEL_SHIFT)
+#endif
+#if defined( _ADC_SINGLECTRL_NEGSEL_MASK )
+        | (init->negSel << _ADC_SINGLECTRL_NEGSEL_SHIFT)
+#endif
+        | ((uint32_t)(init->resolution) << _ADC_SINGLECTRL_RES_SHIFT);
 
   if (init->prsEnable)
   {
@@ -396,10 +855,86 @@
     tmp |= ADC_SINGLECTRL_REP;
   }
 
+  /* Set single reference. Check if reference configuraion is extended to SINGLECTRLX. */
+#if defined ( _ADC_SINGLECTRLX_MASK )
+  if (init->reference & ADC_CTRLX_VREFSEL_REG)
+  {
+    /* Select extension register */
+    tmp |= ADC_SINGLECTRL_REF_CONF;
+  }
+  else
+  {
+    tmp |= (init->reference << _ADC_SINGLECTRL_REF_SHIFT);
+  }
+#else
+  tmp |= (init->reference << _ADC_SINGLECTRL_REF_SHIFT);
+#endif
   adc->SINGLECTRL = tmp;
+
+  /* Update SINGLECTRLX for reference select and PRS select */
+#if defined ( _ADC_SINGLECTRLX_VREFSEL_MASK )
+  tmp = adc->SINGLECTRLX & (_ADC_SINGLECTRLX_VREFSEL_MASK
+                          | _ADC_SINGLECTRLX_PRSSEL_MASK
+                          | _ADC_SINGLECTRLX_FIFOOFACT_MASK);
+  if (init->reference & ADC_CTRLX_VREFSEL_REG)
+  {
+    tmp |= ((init->reference & ~ADC_CTRLX_VREFSEL_REG) << _ADC_SINGLECTRLX_VREFSEL_SHIFT);
+  }
+
+  tmp |= ((init->prsSel << _ADC_SINGLECTRLX_PRSSEL_SHIFT));
+
+  if (init->fifoOverwrite)
+  {
+    tmp |= ADC_SINGLECTRLX_FIFOOFACT_OVERWRITE;
+  }
+
+  adc->SINGLECTRLX = tmp;
+#endif
+
+  /* Set DMA availability in EM2 */
+#if defined( _ADC_CTRL_SINGLEDMAWU_MASK )
+  BUS_RegBitWrite(&ADC0->CTRL, _ADC_CTRL_SINGLEDMAWU_SHIFT, init->singleDmaEm2Wu);
+#endif
+
+  /* Assert for any APORT bus conflicts programming errors */
+#if defined( _ADC_BUSCONFLICT_MASK )
+  tmp = adc->BUSREQ;
+  EFM_ASSERT(!(tmp & adc->BUSCONFLICT));
+  EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK));
+#endif
 }
 
 
+#if defined( _ADC_SCANDATAX_MASK )
+/***************************************************************************//**
+ * @brief
+ *   Get scan result and scan select ID.
+ *
+ * @note
+ *   Only use if scan data valid. This function does not check the DV flag.
+ *   The return value is intended to be used as a index for the scan select ID.
+ *
+ * @param[in] adc
+ *   Pointer to ADC peripheral register block.
+ *
+ * @param[out] scanId
+ *   Scan select ID of first data in scan FIFO.
+ *
+ * @return
+ *   First scan data in scan FIFO.
+ ******************************************************************************/
+uint32_t ADC_DataIdScanGet(ADC_TypeDef *adc, uint32_t *scanId)
+{
+  uint32_t scanData;
+
+  /* Pop data FIFO with scan ID */
+  scanData = adc->SCANDATAX;
+  *scanId = (scanData & _ADC_SCANDATAX_SCANINPUTID_MASK) >> _ADC_SCANDATAX_SCANINPUTID_SHIFT;
+  return (scanData & _ADC_SCANDATAX_DATA_MASK) >> _ADC_SCANDATAX_DATA_SHIFT;
+}
+#endif
+
+
 /***************************************************************************//**
  * @brief
  *   Calculate prescaler value used to determine ADC clock.
@@ -461,19 +996,42 @@
 void ADC_Reset(ADC_TypeDef *adc)
 {
   /* Stop conversions, before resetting other registers. */
-  adc->CMD        = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
-  adc->SINGLECTRL = _ADC_SINGLECTRL_RESETVALUE;
-  adc->SCANCTRL   = _ADC_SCANCTRL_RESETVALUE;
-  adc->CTRL       = _ADC_CTRL_RESETVALUE;
-  adc->IEN        = _ADC_IEN_RESETVALUE;
-  adc->IFC        = _ADC_IFC_MASK;
-  adc->BIASPROG   = _ADC_BIASPROG_RESETVALUE;
+  adc->CMD          = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
+  adc->SINGLECTRL   = _ADC_SINGLECTRL_RESETVALUE;
+#if defined( _ADC_SINGLECTRLX_MASK )
+  adc->SINGLECTRLX  = _ADC_SINGLECTRLX_RESETVALUE;
+#endif
+  adc->SCANCTRL     = _ADC_SCANCTRL_RESETVALUE;
+#if defined( _ADC_SCANCTRLX_MASK )
+  adc->SCANCTRLX    = _ADC_SCANCTRLX_RESETVALUE;
+#endif
+  adc->CTRL         = _ADC_CTRL_RESETVALUE;
+  adc->IEN          = _ADC_IEN_RESETVALUE;
+  adc->IFC          = _ADC_IFC_MASK;
+  adc->BIASPROG     = _ADC_BIASPROG_RESETVALUE;
+#if defined( _ADC_SCANMASK_MASK )
+  adc->SCANMASK     = _ADC_SCANMASK_RESETVALUE;
+#endif
+#if defined( _ADC_SCANINPUTSEL_MASK )
+  adc->SCANINPUTSEL = _ADC_SCANINPUTSEL_RESETVALUE;
+#endif
+#if defined( _ADC_SCANNEGSEL_MASK )
+  adc->SCANNEGSEL   = _ADC_SCANNEGSEL_RESETVALUE;
+#endif
+
+  /* Clear data FIFOs */
+#if defined( _ADC_SINGLEFIFOCLEAR_MASK )
+  adc->SINGLEFIFOCLEAR |= ADC_SINGLEFIFOCLEAR_SINGLEFIFOCLEAR;
+  adc->SCANFIFOCLEAR   |= ADC_SCANFIFOCLEAR_SCANFIFOCLEAR;
+#endif
 
   /* Load calibration values for the 1V25 internal reference. */
-  ADC_CalibrateLoadSingle(adc, adcRef1V25);
-  ADC_CalibrateLoadScan(adc, adcRef1V25);
+  ADC_LoadDevinfoCal(adc, adcRef1V25, false);
+  ADC_LoadDevinfoCal(adc, adcRef1V25, true);
 
+#if defined( _ADC_SCANINPUTSEL_MASK )
   /* Do not reset route register, setting should be done independently */
+#endif
 }
 
 
@@ -499,13 +1057,13 @@
       hfperFreq = 1;
     }
   }
-#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+#if defined( _EFM32_GIANT_FAMILY ) || defined( _EFM32_WONDER_FAMILY )
   /* Handle errata on Giant Gecko, max TIMEBASE is 5 bits wide or max 0x1F */
   /* cycles. This will give a warmp up time of e.g. 0.645us, not the       */
   /* required 1us when operating at 48MHz. One must also increase acqTime  */
   /* to compensate for the missing clock cycles, adding up to 1us in total.*/
   /* See reference manual for details. */
-  if( hfperFreq > 32000000 )
+  if ( hfperFreq > 32000000 )
   {
     hfperFreq = 32000000;
   }