/** 
 * \file oscillators.h
 * \brief oscillators header file
 * \details File contains structures, enumerations and functions declarations for configure oscillators
 *
 * \author Juraj Golej
 * \version 1.0
 * 
 * \todo [oscillators] OSC functions for slow clock (SLCK)
 * \todo [oscillators] OSC functions for USB UTMI PLL (UPLLCLK)
 */


#ifndef OSCILLATORS_H_
#define OSCILLATORS_H_

#include "sam.h"
#include <stdbool.h>
#include <utils/retcode/retcode.h>

#define CFG_OSC_CRYSTAL_FREQ 12000000UL	///< External oscillator frequency

/** 
 * \brief Internal RC oscillator frequencies enumeration
 */
enum OSC_rc_freq {
	OSC_FREQ_4MHz,	///< 4 MHz internal RC oscillator
	OSC_FREQ_8MHz,	///< 8 MHz internal RC oscillator
	OSC_FREQ_12MHz,	///< 12 MHz internal RC oscillator
}; /* enum OSC_rc_freq */

/**
 * \brief Enable external crystal oscillator (3 to 20 MHz)
 * 
 * \param[in] startUpTime Startup time in SLCK cycles
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone Everything OK
 * \retval EHardwareProblem External crystal isn't connected
 */
enum retCode OSC_mainck_crystal_enable(const uint8_t startUpTime);

/**
 * \brief Disable external crystal oscillator.
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone Everything OK
 * \retval EDenied Crystal oscillator is the source for MAINCK
 */
enum retCode OSC_mainck_crystal_disable();

/**
 * \brief Enable internal RC oscillator
 * 
 * \param[in] freq Frequency of RC oscillator
 */
void OSC_mainck_rc_enable(const enum OSC_rc_freq freq);

/**
 * \brief Disable internal RC oscillator
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone Everything OK
 * \retval EDenied RC oscillator is the source for MAINCK
 */
enum retCode OSC_mainck_rc_disable();

/**
 * \brief Select the oscillator source for MAINCK
 * 
 * \param[in] crystal \c true for external crystal, \c false for RC oscillator
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone Everything OK
 * \retval EDenied The selected source can't be switched, because it isn't stabilized
 */
enum retCode OSC_mainck_select(const bool crystal);

/**
 * \brief Enable PLLA with user defined frequency by \c div and \c mul
 * 
 * \param[in] div Divider of MAINCK frequency
 * \param[in] mul Multiplication of divided MAINCK frequency
 * \param[in] startUpTime Startup time in SLCK cycles 
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone Everything OK
 * \retval EInvalidParameter \c div or \c mul parameter is zero (PLLA will be disabled), or calculated PLLA frequency isn't in interval 160 to 500 MHz
 * \retval EDenied Input MAINCK frequency is lower than 8 MHz
 * 
 * \note fPLLA = fMAINCK * (mul + 1)/div
 */
enum retCode OSC_plla_enable(const uint8_t div, const uint16_t mul, const uint8_t startUpTime);

/**
 * \brief Disable PLLA
 */
void OSC_plla_disable();

/**
 * \brief Get actual MAINCK frequency
 * 
 * \return \c uint32_t Actual MAINCK frequency
 */
uint32_t OSC_get_mainck_freq();

/**
 * \brief Get actual PLLA frequency
 * 
 * \return \c uint32_t Actual PLLA frequency
 */
uint32_t OSC_get_plla_freq();

/**
 * \brief Get actual UPLL frequency
 * 
 * \return \c uint32_t Actual UPLL frequency
 */
uint32_t OSC_get_upll_freq();

/**
 * \brief Get actual SLCK frequency
 * 
 * \return \c uint32_t Actual SLCK frequency
 */
uint32_t OSC_get_slck_freq();


#endif /* OSCILLATORS_H_ */