The original submitter of this squished everything into one series, and has not returned. The code mostly appears good, and review comments were followed for the most part. The project doesn't really maintain any testing or board farm for sam3/sam4 parts, so we're going to just trust our users. Reviewed-by: Karl Palsson <karlp@tweak.net.au> sam/4l: IRQ Configuration file (irq.json) sam/4l: Basic Memory Map. sam/4l: GPIO Defines. sam/4l: GPIO Functions Added everything that needed to compile the library: Makefile, Linker Script and common includes. sam/4l: SCIF function to start OSC. sam/4l: GPIO Enable/Disable and Multiplexing configuration functions. sam/4l: PLL Clock configuration. sam/4l: Peripheral clock configuration and basic USART support. sam: USART Character length configuration. sam/4l: Generic Clock configuration functions. sam/4l: Analog to Digital Converter Interface (ADCIFE) basic support.
134 lines
4.2 KiB
C
134 lines
4.2 KiB
C
/** @addtogroup scif
|
|
*
|
|
* @brief <b>Access functions for the SAM4 System Controf Interface (SCIF)</b>
|
|
* @ingroup SAM4
|
|
* LGPL License Terms @ref lgpl_license
|
|
* @author @htmlonly © @endhtmlonly 2016
|
|
* Maxim Sloyko <maxims@google.com>
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This file is part of the libopencm3 project.
|
|
*
|
|
* This library is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <libopencm3/sam/scif.h>
|
|
|
|
/** @brief Enable external oscillator.
|
|
*
|
|
* @param[in] mode enum osc_mode: Oscillator mode (which pins oscillator connected to).
|
|
* @param[in] freq uint32_t: External Oscillator frequency, in Hertz. Must be 0.6MHz - 30MHz
|
|
* @param[in] startup enum osc_startup: Oscillator start time in RCSYS clock cycles.
|
|
*
|
|
* @returns zero upon success.
|
|
*/
|
|
int scif_osc_enable(enum osc_mode mode, uint32_t freq, enum osc_startup startup)
|
|
{
|
|
uint8_t gain;
|
|
const uint32_t kHz = 1000;
|
|
const uint32_t MHz = 1000 * kHz;
|
|
|
|
if (freq > 600 * kHz && freq <= 2 * MHz) {
|
|
gain = 0;
|
|
} else if (freq > 2 * MHz && freq <= 4 * MHz) {
|
|
gain = 1;
|
|
} else if (freq > 4 * MHz && freq <= 8 * MHz) {
|
|
gain = 2;
|
|
} else if (freq > 8 * MHz && freq <= 16 * MHz) {
|
|
gain = 3;
|
|
} else if (freq > 16 * MHz && freq <= 30 * MHz) {
|
|
gain = 4;
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
SCIF_UNLOCK = SCIF_OSCCTRL0_KEY;
|
|
SCIF_OSCCTRL0 = mode | SCIF_OSCCTRL_OSCEN |
|
|
(gain << SCIF_OSCCTRL_GAIN_SHIFT) | (startup << SCIF_OSCCTRL_STARTUP_SHIFT);
|
|
|
|
while (!(SCIF_PCLKSR & SCIF_OSC0RDY));
|
|
return 0;
|
|
}
|
|
|
|
/** @brief Configure and enable PLL clock.
|
|
*
|
|
* @param[in] delay uint8_t: Specifies the number of RCSYS clock cycles before
|
|
* ISR.PLLLOCKn will be set after PLL has been written, or after PLL has
|
|
* been automatically re-enabled after exiting a sleep mode.
|
|
* @param[in] mul uint8_t: Multiply factor.
|
|
* @param[in] div uint8_t: Division factor.These fields determine the ratio of
|
|
* the PLL output frequency to the source oscillator frequency:
|
|
* f_vco = (PLLMUL+1)/PLLDIV * f_ref if PLLDIV >0
|
|
* f_vco = 2*(PLLMUL+1) * f_ref if PLLDIV = 0
|
|
* Note that the PLLMUL field should always be greater than 1 or the
|
|
* behavior of the PLL will be undefined.
|
|
* @param[in] pll_opt uint8_t: PLL Options.
|
|
* @param[in] pll_opt uint8_t: PLL Options.
|
|
*
|
|
* @returns zero upon success.
|
|
*/
|
|
int scif_enable_pll(uint8_t delay, uint8_t mul, uint8_t div, uint8_t pll_opt, enum pll_clk_src source_clock)
|
|
{
|
|
// First, PLL needs to be disabled, otherwise the configuration register
|
|
// is unaccessible.
|
|
uint32_t pll_val = SCIF_PLL0;
|
|
if (pll_val & SCIF_PLL0_PLLEN) {
|
|
SCIF_UNLOCK = SCIF_PLL0_KEY;
|
|
SCIF_PLL0 = pll_val & (~SCIF_PLL0_PLLEN);
|
|
}
|
|
|
|
if (mul == 0)
|
|
mul = 1;
|
|
|
|
pll_val = SCIF_PLL0_PLLOSC_MASKED(source_clock)
|
|
| SCIF_PLL0_PLLOPT_MASKED(pll_opt)
|
|
| SCIF_PLL0_PLLDIV_MASKED(div)
|
|
| SCIF_PLL0_PLLMUL_MASKED(mul)
|
|
| SCIF_PLL0_PLLCOUNT_MASKED(delay);
|
|
|
|
SCIF_UNLOCK = SCIF_PLL0_KEY;
|
|
SCIF_PLL0 = pll_val;
|
|
|
|
// Now enable TODO: does this really need to be separate operation?
|
|
SCIF_UNLOCK = SCIF_PLL0_KEY;
|
|
SCIF_PLL0 = pll_val | SCIF_PLL0_PLLEN;
|
|
|
|
while(!(SCIF_PCLKSR & SCIF_PLL0LOCK));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** @brief Configure and enable Generic Clock
|
|
*
|
|
* @param[in] gclk enum generic_clock: Generic Clock to configure and enable.
|
|
* @param[in] source_clock enum gclk_src: Source Clock for this Generic Clock.
|
|
* @param[in] div uint16_t: Division Factor. Upper 8 bits only used for Generic Clock 11,
|
|
* If 0, clock is undivided.
|
|
*/
|
|
void scif_enable_gclk(enum generic_clock gclk, enum gclk_src source_clock, uint16_t div)
|
|
{
|
|
uint32_t reg_val = SCIF_GCCTRL_CEN | SCIF_GCCTRL_OSCSEL_MASKED(source_clock);
|
|
if (div) {
|
|
if (gclk < GENERIC_CLOCK11) {
|
|
div &= 0xf;
|
|
}
|
|
|
|
reg_val |= SCIF_GCCTRL_DIV_MASKED(div) | SCIF_GCCTRL_DIVEN;
|
|
}
|
|
|
|
SCIF_GCTRL(gclk) = reg_val;
|
|
}
|