/**
 * \file
 *
 * \brief SAM ADC functionality
 *
 * Copyright (c) 2014-2020 Microchip Technology Inc. and its subsidiaries.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Subject to your compliance with these terms, you may use Microchip
 * software and any derivatives exclusively with Microchip products.
 * It is your responsibility to comply with third party license terms applicable
 * to your use of third party software (including open source software) that
 * may accompany Microchip software.
 *
 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
 *
 * \asf_license_stop
 *
 */
/*
 * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
 */
#ifndef ADC_FEATURE_H_INCLUDED
#define ADC_FEATURE_H_INCLUDED

/**
 * \addtogroup asfdoc_sam0_adc_group
 * @{
 */

#ifdef __cplusplus
extern "C" {
#endif

/*@{*/
#if (SAMC20) || (SAMC21) || defined(__DOXYGEN__)
/** Output Driver Strength Selection feature support. */
#  define FEATURE_ADC_SUPPORT_MASTER_SLAVE
#endif
/*@}*/

#if ADC_CALLBACK_MODE == true
#  include <system_interrupt.h>

#if !defined(__DOXYGEN__)
extern struct adc_module *_adc_instances[ADC_INST_NUM];
#endif

/** Forward definition of the device instance. */
struct adc_module;

/** Type of the callback functions. */
typedef void (*adc_callback_t)(struct adc_module *const module);

/**
 * \brief ADC callback enum.
 *
 * Callback types for ADC callback driver.
 *
 */
enum adc_callback {
	/** Callback for buffer received */
	ADC_CALLBACK_READ_BUFFER,
	/** Callback when window is hit */
	ADC_CALLBACK_WINDOW,
	/** Callback for error */
	ADC_CALLBACK_ERROR,
#  if !defined(__DOXYGEN__)
	/** Number of available callbacks */
	ADC_CALLBACK_N,
#  endif
};

#endif

/**
 * \brief ADC reference voltage enum.
 *
 * Enum for the possible reference voltages for the ADC.
 *
 */
enum adc_reference {
	/** Internal Bandgap Reference */
	ADC_REFERENCE_INTREF  = ADC_REFCTRL_REFSEL_INTREF,
	/** 1/1.48V<SUB>CC</SUB> reference */
	ADC_REFERENCE_INTVCC0 = ADC_REFCTRL_REFSEL_INTVCC0,
	/** 1/2V<SUB>CC</SUB> (only for internal V<SUB>CC</SUB> > 2.1V) */
	ADC_REFERENCE_INTVCC1 = ADC_REFCTRL_REFSEL_INTVCC1,
	/** External reference A */
	ADC_REFERENCE_AREFA   = ADC_REFCTRL_REFSEL_AREFA,
#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
	/** External reference B */
	ADC_REFERENCE_AREFB   = ADC_REFCTRL_REFSEL_AREFB,
#endif
#if (SAMC20) || (SAMC21)
	/** DAC */
	ADC_REFERENCE_DAC     = ADC_REFCTRL_REFSEL_DAC,
#endif
	/** VDDANA */
	ADC_REFERENCE_INTVCC2 = ADC_REFCTRL_REFSEL_INTVCC2,
};

/**
 * \brief ADC clock prescaler enum.
 *
 * Enum for the possible clock prescaler values for the ADC.
 *
 */
enum adc_clock_prescaler {
	/** ADC clock division factor 2 */
	ADC_CLOCK_PRESCALER_DIV2   = ADC_CTRLB_PRESCALER_DIV2,
	/** ADC clock division factor 4 */
	ADC_CLOCK_PRESCALER_DIV4   = ADC_CTRLB_PRESCALER_DIV4,
	/** ADC clock division factor 8 */
	ADC_CLOCK_PRESCALER_DIV8   = ADC_CTRLB_PRESCALER_DIV8,
	/** ADC clock division factor 16 */
	ADC_CLOCK_PRESCALER_DIV16  = ADC_CTRLB_PRESCALER_DIV16,
	/** ADC clock division factor 32 */
	ADC_CLOCK_PRESCALER_DIV32  = ADC_CTRLB_PRESCALER_DIV32,
	/** ADC clock division factor 64 */
	ADC_CLOCK_PRESCALER_DIV64  = ADC_CTRLB_PRESCALER_DIV64,
	/** ADC clock division factor 128 */
	ADC_CLOCK_PRESCALER_DIV128 = ADC_CTRLB_PRESCALER_DIV128,
	/** ADC clock division factor 256 */
	ADC_CLOCK_PRESCALER_DIV256 = ADC_CTRLB_PRESCALER_DIV256,
};

/**
 * \brief ADC resolution enum.
 *
 * Enum for the possible resolution values for the ADC.
 *
 */
enum adc_resolution {
	/** ADC 12-bit resolution */
	ADC_RESOLUTION_12BIT = ADC_CTRLC_RESSEL_12BIT,
	/** ADC 16-bit resolution using oversampling and decimation */
	ADC_RESOLUTION_16BIT = ADC_CTRLC_RESSEL_16BIT,
	/** ADC 10-bit resolution */
	ADC_RESOLUTION_10BIT = ADC_CTRLC_RESSEL_10BIT,
	/** ADC 8-bit resolution */
	ADC_RESOLUTION_8BIT  = ADC_CTRLC_RESSEL_8BIT,
	/** ADC 13-bit resolution using oversampling and decimation */
	ADC_RESOLUTION_13BIT,
	/** ADC 14-bit resolution using oversampling and decimation */
	ADC_RESOLUTION_14BIT,
	/** ADC 15-bit resolution using oversampling and decimation */
	ADC_RESOLUTION_15BIT,
	/** ADC 16-bit result register for use with averaging. When using this mode
	  * the ADC result register will be set to 16-bit wide, and the number of
	  * samples to accumulate and the division factor is configured by the
	  * \ref adc_config.accumulate_samples and \ref adc_config.divide_result
	  * members in the configuration struct.
	  */
	ADC_RESOLUTION_CUSTOM,
};

/**
 * \brief ADC window monitor mode enum.
 *
 * Enum for the possible window monitor modes for the ADC.
 *
 */
enum adc_window_mode {
	/** No window mode */
	ADC_WINDOW_MODE_DISABLE          = ADC_CTRLC_WINMODE_DISABLE,
	/** RESULT > WINLT */
	ADC_WINDOW_MODE_ABOVE_LOWER      = ADC_CTRLC_WINMODE_MODE1,
	/** RESULT < WINUT */
	ADC_WINDOW_MODE_BELOW_UPPER      = ADC_CTRLC_WINMODE_MODE2,
	/** WINLT < RESULT < WINUT */
	ADC_WINDOW_MODE_BETWEEN          = ADC_CTRLC_WINMODE_MODE3,
	/** !(WINLT < RESULT < WINUT) */
	ADC_WINDOW_MODE_BETWEEN_INVERTED = ADC_CTRLC_WINMODE_MODE4,
};

/**
 * \brief ADC event action enum.
 *
 * Enum for the possible actions to take on an incoming event.
 *
 */
enum adc_event_action {
	/** Event action disabled */
	ADC_EVENT_ACTION_DISABLED         = 0,
	/** Flush ADC and start conversion */
	ADC_EVENT_ACTION_FLUSH_START_CONV = ADC_EVCTRL_FLUSHEI,
	/** Start conversion */
	ADC_EVENT_ACTION_START_CONV       = ADC_EVCTRL_STARTEI,
};

/**
 * \brief ADC positive MUX input selection enum.
 *
 * Enum for the possible positive MUX input selections for the ADC.
 *
 */
enum adc_positive_input {
	/** ADC0 pin */
	ADC_POSITIVE_INPUT_PIN0          = ADC_INPUTCTRL_MUXPOS_AIN0,
	/** ADC1 pin */
	ADC_POSITIVE_INPUT_PIN1          = ADC_INPUTCTRL_MUXPOS_AIN1,
	/** ADC2 pin */
	ADC_POSITIVE_INPUT_PIN2          = ADC_INPUTCTRL_MUXPOS_AIN2,
	/** ADC3 pin */
	ADC_POSITIVE_INPUT_PIN3          = ADC_INPUTCTRL_MUXPOS_AIN3,
	/** ADC4 pin */
	ADC_POSITIVE_INPUT_PIN4          = ADC_INPUTCTRL_MUXPOS_AIN4,
	/** ADC5 pin */
	ADC_POSITIVE_INPUT_PIN5          = ADC_INPUTCTRL_MUXPOS_AIN5,
	/** ADC6 pin */
	ADC_POSITIVE_INPUT_PIN6          = ADC_INPUTCTRL_MUXPOS_AIN6,
	/** ADC7 pin */
	ADC_POSITIVE_INPUT_PIN7          = ADC_INPUTCTRL_MUXPOS_AIN7,
	/** ADC8 pin */
	ADC_POSITIVE_INPUT_PIN8          = ADC_INPUTCTRL_MUXPOS_AIN8,
	/** ADC9 pin */
	ADC_POSITIVE_INPUT_PIN9          = ADC_INPUTCTRL_MUXPOS_AIN9,
	/** ADC10 pin */
	ADC_POSITIVE_INPUT_PIN10         = ADC_INPUTCTRL_MUXPOS_AIN10,
	/** ADC11 pin */
	ADC_POSITIVE_INPUT_PIN11         = ADC_INPUTCTRL_MUXPOS_AIN11,
#if !(SAMC20) && !(SAMC21)
	/** ADC12 pin */
	ADC_POSITIVE_INPUT_PIN12         = ADC_INPUTCTRL_MUXPOS_AIN12,
	/** ADC13 pin */
	ADC_POSITIVE_INPUT_PIN13         = ADC_INPUTCTRL_MUXPOS_AIN13,
	/** ADC14 pin */
	ADC_POSITIVE_INPUT_PIN14         = ADC_INPUTCTRL_MUXPOS_AIN14,
	/** ADC15 pin */
	ADC_POSITIVE_INPUT_PIN15         = ADC_INPUTCTRL_MUXPOS_AIN15,
	/** ADC16 pin */
	ADC_POSITIVE_INPUT_PIN16         = ADC_INPUTCTRL_MUXPOS_AIN16,
	/** ADC17 pin */
	ADC_POSITIVE_INPUT_PIN17         = ADC_INPUTCTRL_MUXPOS_AIN17,
	/** ADC18 pin */
	ADC_POSITIVE_INPUT_PIN18         = ADC_INPUTCTRL_MUXPOS_AIN18,
	/** ADC19 pin */
	ADC_POSITIVE_INPUT_PIN19         = ADC_INPUTCTRL_MUXPOS_AIN19,
#if !(SAML22 || SAMR30 || SAMR34 || SAMR35 || (WLR089))
	/** ADC20 pin. */
	ADC_POSITIVE_INPUT_PIN20         = ADC_INPUTCTRL_MUXPOS_AIN20,
	/** ADC21 pin */
	ADC_POSITIVE_INPUT_PIN21         = ADC_INPUTCTRL_MUXPOS_AIN21,
	/** ADC22 pin */
	ADC_POSITIVE_INPUT_PIN22         = ADC_INPUTCTRL_MUXPOS_AIN22,
	/** ADC23 pin */
	ADC_POSITIVE_INPUT_PIN23         = ADC_INPUTCTRL_MUXPOS_AIN23,
#endif
	/** Temperature reference. */
	ADC_POSITIVE_INPUT_TEMP          = ADC_INPUTCTRL_MUXPOS_TEMP,
#endif
	/** Bandgap voltage */
	ADC_POSITIVE_INPUT_BANDGAP       = ADC_INPUTCTRL_MUXPOS_BANDGAP,
	/** 1/4 scaled core supply */
	ADC_POSITIVE_INPUT_SCALEDCOREVCC = ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC,
	/** 1/4 scaled I/O supply */
	ADC_POSITIVE_INPUT_SCALEDIOVCC   = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC,
#if !(SAML22|| SAMR30 || SAMR34 || SAMR35 || (WLR089))
	/** DAC input */
	ADC_POSITIVE_INPUT_DAC           = ADC_INPUTCTRL_MUXPOS_DAC,
#endif

#if (SAML21)
	/** SCALEDVBAT */
	ADC_POSITIVE_INPUT_SCALEDVBAT    = ADC_INPUTCTRL_MUXPOS_SCALEDVBAT,
	/** OPAMP01 */
	ADC_POSITIVE_INPUT_OPAMP01       = ADC_INPUTCTRL_MUXPOS_OPAMP01,
	/** OPAMP02 */
	ADC_POSITIVE_INPUT_OPAMP2        = ADC_INPUTCTRL_MUXPOS_OPAMP2,
#endif
#if (SAML22)
	/** SCALEDVBAT */
	ADC_POSITIVE_INPUT_SCALEDVBAT    = ADC_INPUTCTRL_MUXPOS_SCALEDVBAT,
	/** CTAT. */
	ADC_POSITIVE_INPUT_CTAT          = ADC_INPUTCTRL_MUXPOS_CTAT,
#endif
};

/**
 * \brief ADC negative MUX input selection enum.
 *
 * Enum for the possible negative MUX input selections for the ADC.
 *
 */
enum adc_negative_input {
	/** ADC0 pin */
	ADC_NEGATIVE_INPUT_PIN0          = ADC_INPUTCTRL_MUXNEG_AIN0,
	/** ADC1 pin */
	ADC_NEGATIVE_INPUT_PIN1          = ADC_INPUTCTRL_MUXNEG_AIN1,
	/** ADC2 pin */
	ADC_NEGATIVE_INPUT_PIN2          = ADC_INPUTCTRL_MUXNEG_AIN2,
	/** ADC3 pin */
	ADC_NEGATIVE_INPUT_PIN3          = ADC_INPUTCTRL_MUXNEG_AIN3,
	/** ADC4 pin */
	ADC_NEGATIVE_INPUT_PIN4          = ADC_INPUTCTRL_MUXNEG_AIN4,
	/** ADC5 pin */
	ADC_NEGATIVE_INPUT_PIN5          = ADC_INPUTCTRL_MUXNEG_AIN5,
#if !(SAMC20) && !(SAMC21) && !(SAMR30) && !(SAMR34) && !(SAMR35) && !(WLR089)
	/** ADC6 pin */
	ADC_NEGATIVE_INPUT_PIN6          = ADC_INPUTCTRL_MUXNEG_AIN6,
	/** ADC7 pin */
	ADC_NEGATIVE_INPUT_PIN7          = ADC_INPUTCTRL_MUXNEG_AIN7,
#endif
	/** Internal ground */
	ADC_NEGATIVE_INPUT_GND           = ADC_INPUTCTRL_MUXNEG(0x18u),
};

/**
 * \brief ADC number of accumulated samples enum.
 *
 * Enum for the possible numbers of ADC samples to accumulate.
 * This setting is only used when the \ref ADC_RESOLUTION_CUSTOM
 * resolution setting is used.
 *
 */
enum adc_accumulate_samples {
	/** No averaging */
	ADC_ACCUMULATE_DISABLE      = ADC_AVGCTRL_SAMPLENUM_1,
	/** Average 2 samples */
	ADC_ACCUMULATE_SAMPLES_2    = ADC_AVGCTRL_SAMPLENUM_2,
	/** Average 4 samples */
	ADC_ACCUMULATE_SAMPLES_4    = ADC_AVGCTRL_SAMPLENUM_4,
	/** Average 8 samples */
	ADC_ACCUMULATE_SAMPLES_8    = ADC_AVGCTRL_SAMPLENUM_8,
	/** Average 16 samples */
	ADC_ACCUMULATE_SAMPLES_16   = ADC_AVGCTRL_SAMPLENUM_16,
	/** Average 32 samples */
	ADC_ACCUMULATE_SAMPLES_32   = ADC_AVGCTRL_SAMPLENUM_32,
	/** Average 64 samples */
	ADC_ACCUMULATE_SAMPLES_64   = ADC_AVGCTRL_SAMPLENUM_64,
	/** Average 128 samples */
	ADC_ACCUMULATE_SAMPLES_128  = ADC_AVGCTRL_SAMPLENUM_128,
	/** Average 256 samples */
	ADC_ACCUMULATE_SAMPLES_256  = ADC_AVGCTRL_SAMPLENUM_256,
	/** Average 512 samples */
	ADC_ACCUMULATE_SAMPLES_512  = ADC_AVGCTRL_SAMPLENUM_512,
	/** Average 1024 samples */
	ADC_ACCUMULATE_SAMPLES_1024 = ADC_AVGCTRL_SAMPLENUM_1024,
};

/**
 * \brief ADC possible dividers for the result register.
 *
 * Enum for the possible division factors to use when accumulating
 * multiple samples. To keep the same resolution for the averaged
 * result and the actual input value, the division factor must
 * be equal to the number of samples accumulated. This setting is only
 * used when the \ref ADC_RESOLUTION_CUSTOM resolution setting is used.
 */
enum adc_divide_result {
	/** Don't divide result register after accumulation */
	ADC_DIVIDE_RESULT_DISABLE = 0,
	/** Divide result register by 2 after accumulation */
	ADC_DIVIDE_RESULT_2       = 1,
	/** Divide result register by 4 after accumulation */
	ADC_DIVIDE_RESULT_4       = 2,
	/** Divide result register by 8 after accumulation */
	ADC_DIVIDE_RESULT_8       = 3,
	/** Divide result register by 16 after accumulation */
	ADC_DIVIDE_RESULT_16      = 4,
	/** Divide result register by 32 after accumulation */
	ADC_DIVIDE_RESULT_32      = 5,
	/** Divide result register by 64 after accumulation */
	ADC_DIVIDE_RESULT_64      = 6,
	/** Divide result register by 128 after accumulation */
	ADC_DIVIDE_RESULT_128     = 7,
};

#if ADC_CALLBACK_MODE == true
/**
 * Enum for the possible ADC interrupt flags.
 */
enum adc_interrupt_flag {
	/** ADC result ready */
	ADC_INTERRUPT_RESULT_READY = ADC_INTFLAG_RESRDY,
	/** Window monitor match */
	ADC_INTERRUPT_WINDOW       = ADC_INTFLAG_WINMON,
	/** ADC result overwritten before read */
	ADC_INTERRUPT_OVERRUN      = ADC_INTFLAG_OVERRUN,
};
#endif

/**
 * \brief ADC oversampling and decimation enum.
 *
 * Enum for the possible numbers of bits resolution can be increased by when
 * using oversampling and decimation.
 *
 */
enum adc_oversampling_and_decimation {
	/** Don't use oversampling and decimation mode */
	ADC_OVERSAMPLING_AND_DECIMATION_DISABLE = 0,
	/** 1-bit resolution increase */
	ADC_OVERSAMPLING_AND_DECIMATION_1BIT,
	/** 2-bit resolution increase */
	ADC_OVERSAMPLING_AND_DECIMATION_2BIT,
	/** 3-bit resolution increase */
	ADC_OVERSAMPLING_AND_DECIMATION_3BIT,
	/** 4-bit resolution increase */
	ADC_OVERSAMPLING_AND_DECIMATION_4BIT
};

#ifdef FEATURE_ADC_SUPPORT_MASTER_SLAVE
/**
 * Enum for the trigger selection in dual mode.
 */
enum adc_dual_mode_trigger_selection {
	/** Start event or software trigger will start a conversion on both ADCs */
	ADC_DUAL_MODE_BOTH         = ADC_CTRLC_DUALSEL_BOTH,
	/** START event or software trigger will alternatingly start a conversion on ADC0 and ADC1 */
	ADC_DUAL_MODE_INTERLEAVE   = ADC_CTRLC_DUALSEL_INTERLEAVE,
};
#endif

/**
 * \brief Window monitor configuration structure.
 *
 * Window monitor configuration structure.
 */
struct adc_window_config {
	/** Selected window mode */
	enum adc_window_mode window_mode;
	/** Lower window value */
	int32_t window_lower_value;
	/** Upper window value */
	int32_t window_upper_value;
};

/**
 * \brief ADC event enable/disable structure.
 *
 * Event flags for the ADC module. This is used to enable and
 * disable events via \ref adc_enable_events() and \ref adc_disable_events().
 */
struct adc_events {
	/** Enable event generation on conversion done */
	bool generate_event_on_conversion_done;
	/** Enable event generation on window monitor */
	bool generate_event_on_window_monitor;
};

/**
 * \brief Gain and offset correction configuration structure.
 *
 * Gain and offset correction configuration structure.
 * Part of the \ref adc_config struct and will  be initialized by
 * \ref adc_get_config_defaults.
 */
struct adc_correction_config {
	/**
	 * Enables correction for gain and offset based on values of gain_correction and
	 * offset_correction if set to true
	 */
	bool correction_enable;
	/**
	 * This value defines how the ADC conversion result is compensated for gain
	 * error before written to the result register. This is a fractional value,
	 * 1-bit integer plus an 11-bit fraction, therefore
	 * 1/2 <= gain_correction < 2. Valid \c gain_correction values ranges from
	 * \c 0b010000000000 to \c 0b111111111111.
	 */
	uint16_t gain_correction;
	/**
	 * This value defines how the ADC conversion result is compensated for
	 * offset error before written to the result register. This is a 12-bit
	 * value in two's complement format.
	 */
	int16_t offset_correction;
};

/**
 * \brief ADC configuration structure.
 *
 * Configuration structure for an ADC instance. This structure should be
 * initialized by the \ref adc_get_config_defaults()
 * function before being modified by the user application.
 */
struct adc_config {
	/** GCLK generator used to clock the peripheral */
	enum gclk_generator clock_source;
	/** Voltage reference */
	enum adc_reference reference;
	/** Clock prescaler */
	enum adc_clock_prescaler clock_prescaler;
	/** Result resolution */
	enum adc_resolution resolution;
	/** Positive MUX input */
	enum adc_positive_input positive_input;
	/** Negative MUX input */
	enum adc_negative_input negative_input;
	/** Number of ADC samples to accumulate when using the
	 *  \c ADC_RESOLUTION_CUSTOM mode
	 */
	enum adc_accumulate_samples accumulate_samples;
	/** Division ration when using the ADC_RESOLUTION_CUSTOM mode */
	enum adc_divide_result divide_result;
	/** Left adjusted result */
	bool left_adjust;
	/** Enables differential mode if true */
	bool differential_mode;
	/** Enables free running mode if true */
	bool freerunning;
	/** ADC run in standby control */
	bool run_in_standby;
	/** ADC On demand control */
	bool on_demand;
	/**
	 * Enables sampling period offset compensation if true
	 */
	bool sampling_time_compensation_enable;
	/**
	 * Positive input enabled mask for conversion sequence.
	 * The sequence start from the lowest input, and go to the next enabled input
	 * automatically when the conversion is done. If no bits are set the
	 * sequence is disabled.
	 */
	uint32_t positive_input_sequence_mask_enable;
	/**
	 * Enables reference buffer offset compensation if true.
	 * This will increase the accuracy of the gain stage, but decreases the input
	 * impedance; therefore the startup time of the reference must be increased.
	 */
	bool reference_compensation_enable;
	/**
	 * This value (0-63) control the ADC sampling time in number of half ADC
	 * prescaled clock cycles (depends of \c ADC_PRESCALER value), thus
	 * controlling the ADC input impedance. Sampling time is set according to
	 * the formula:
	 * Sample time = (sample_length+1) * (ADCclk / 2).
	 */
	uint8_t sample_length;
	/** Window monitor configuration structure */
	struct adc_window_config window;
	/** Gain and offset correction configuration structure */
	struct adc_correction_config correction;
	/** Event action to take on incoming event */
	enum adc_event_action event_action;
};

/**
 * \brief ADC software device instance structure.
 *
 * ADC software instance structure, used to retain software state information
 * of an associated hardware module instance.
 *
 * \note The fields of this structure should not be altered by the user
 *       application; they are reserved for module-internal use only.
 */
struct adc_module {
#if !defined(__DOXYGEN__)
	/** Pointer to ADC hardware module */
	Adc *hw;
	/** Keep reference configuration so we know when enable is called */
	enum adc_reference reference;
#  if ADC_CALLBACK_MODE == true
	/** Array to store callback functions */
	adc_callback_t callback[ADC_CALLBACK_N];
	/** Pointer to buffer used for ADC results */
	volatile uint16_t *job_buffer;
	/** Remaining number of conversions in current job */
	volatile uint16_t remaining_conversions;
	/** Bit mask for callbacks registered */
	uint8_t registered_callback_mask;
	/** Bit mask for callbacks enabled */
	uint8_t enabled_callback_mask;
	/** Holds the status of the ongoing or last conversion job */
	volatile enum status_code job_status;
	/** If software triggering is needed */
	bool software_trigger;
#  endif
#endif
};

#if !defined(__DOXYGEN__)

/**
 * \brief Determines if the hardware module(s) are currently synchronizing to the bus.
 *
 * Checks to see if the underlying hardware peripheral module(s) are currently
 * synchronizing across multiple clock domains to the hardware bus. This
 * function can be used to delay further operations on a module until such time
 * that it is ready, to prevent blocking delays for synchronization in the
 * user application.
 *
 * \param[in] module_inst  Pointer to the ADC software instance struct
 *
 * \return Synchronization status of the underlying hardware module(s).
 *
 * \retval true if the module synchronization is ongoing
 * \retval false if the module has completed synchronization
 */
static inline bool adc_is_syncing(
	struct adc_module *const module_inst)
{
	/* Sanity check arguments */
	Assert(module_inst);

	Adc *const adc_module = module_inst->hw;

	if (adc_module->SYNCBUSY.reg) {
		return true;
	}

	return false;
}
#endif

/**
 * \name  Positive Input Sequence
 * @{
 */

/**
 * \brief Enable positive input sequence mask for conversion.
 *
 * The sequence start from the lowest input, and go to the next enabled input
 * automatically when the conversion is done. If no bits are set the
 * sequence is disabled.
 *
 * \param[in] module_inst  Pointer to the ADC software instance struct
 * \param[in] eanble_seq_mask  Sequence mask
 */
static inline void adc_enable_positive_input_sequence(
		struct adc_module *const module_inst,
		uint32_t positive_input_sequence_mask_enable)
{
	/* Sanity check arguments */
	Assert(module_inst);

	Adc *const adc_module = module_inst->hw;
	adc_module->SEQCTRL.reg = positive_input_sequence_mask_enable;
}

/**
 * \brief Disable positive input in the sequence.
 *
 * Disable positive input in the sequence.
 *
 * \param[in] module_inst  Pointer to the ADC software instance struct
 */
static inline void adc_disable_positive_input_sequence(
		struct adc_module *const module_inst)
{
	/* Sanity check arguments */
	Assert(module_inst);

	Adc *const adc_module = module_inst->hw;
	adc_module->SEQCTRL.reg = 0;
}

/**
 * \brief Get ADC sequence status.
 *
 * Check if a sequence is done and get last conversion done in the sequence.
 *
 * \param[in] module_inst  Pointer to the ADC software instance struct
 * \param[out] is_sequence_busy  Sequence busy status
 * \param[out] sequence_state This value identifies the last conversion
 *             done in the sequence
 */
static inline void adc_get_sequence_status(
		struct adc_module *const module_inst,
		bool  * is_sequence_busy,
		uint8_t *sequence_state)
{
	/* Sanity check arguments */
	Assert(module_inst);
	uint8_t temp = false;
	Adc *const adc_module = module_inst->hw;
	temp = adc_module->SEQSTATUS.reg;
	if(temp & ADC_SEQSTATUS_SEQBUSY){
		*is_sequence_busy = true;
	}
	*sequence_state = temp & ADC_SEQSTATUS_SEQSTATE_Msk;
}

/** @} */

#ifdef FEATURE_ADC_SUPPORT_MASTER_SLAVE
/**
 * \brief Set ADC master and slave mode.
 *
 * Enable ADC module Master-Slave Operation and select dual mode trigger.
 *
 * \param[in] master_inst  Pointer to the master ADC software instance struct
 * \param[in] slave_inst   Pointer to the slave ADC software instance struct
 * \param[in] dualsel      Dual mode trigger selection
 *
 */
static inline void adc_set_master_slave_mode(
		struct adc_module *const master_inst,
		struct adc_module *const slave_inst,
		enum adc_dual_mode_trigger_selection dualsel)
{
	/* Sanity check arguments */
	Assert(master_inst);
	Assert(slave_inst);

	slave_inst->hw->CTRLA.reg |= ADC_CTRLA_SLAVEEN;
	master_inst->hw->CTRLC.reg |= dualsel;

};
#endif
/** @} */

#ifdef __cplusplus
}
#endif

/** @} */

#endif /* ADC_FEATURE_H_INCLUDED */

