mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
bf96c28889
Generated new vendor header files from upstream SVD files using: ./SVDConv "$PICO_SDK_DIR"/src/rp2040/hardware_regs/rp2040.svd \ --generate=header --fields=macro --fields=enum Note: The missing `--fields=struct` flag resulted in the header no longer containing bit-fields to represent different fields within registers. While this would generally ease writing code, the RP2040 has the unpleasant feature of corrupting the remaining bits of the register when a write access that is not word-sized occurs in the memory mapped I/O area. This could happen e.g. when a bit field is byte-sized and byte-aligned.
119 lines
3.5 KiB
C
119 lines
3.5 KiB
C
/*
|
|
* Copyright (C) 2021 Otto-von-Guericke Universität Magdeburg
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup cpu_rpx0xx
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Implementation of the phase locked loop (PLL)
|
|
* to drive the ROSC or XOSC to a higher frequency
|
|
*
|
|
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
#include "macros/units.h"
|
|
#include "periph_cpu.h"
|
|
#include "vendor/RP2040.h"
|
|
#include "io_reg.h"
|
|
|
|
/**
|
|
* @brief Start the PLL for the system clock (@p pll = PLL_SYS) or
|
|
* the USB clock (@p pll = PLL_USB)
|
|
*/
|
|
static void _pll_start(PLL_SYS_Type *pll, uint8_t ref_div,
|
|
uint16_t vco_feedback_scale,
|
|
uint8_t post_div_1, uint8_t post_div_2)
|
|
{
|
|
assert(PLL_REF_DIV_MIN <= ref_div);
|
|
assert(ref_div <= PLL_REF_DIV_MAX);
|
|
assert(PLL_VCO_FEEDBACK_SCALE_MIN <= vco_feedback_scale);
|
|
assert(vco_feedback_scale <= PLL_VCO_FEEDBACK_SCALE_MAX);
|
|
assert(PLL_POSTDIV_MIN <= post_div_1);
|
|
assert(post_div_1 <= PLL_POSTDIV_MAX);
|
|
assert(PLL_POSTDIV_MIN <= post_div_2);
|
|
assert(post_div_2 <= PLL_POSTDIV_MAX);
|
|
|
|
/* program reference clock divider */
|
|
io_reg_write_dont_corrupt(&pll->CS, ref_div << PLL_SYS_CS_REFDIV_Pos,
|
|
PLL_SYS_CS_REFDIV_Msk);
|
|
/* program feedback divider */
|
|
io_reg_write_dont_corrupt(&pll->FBDIV_INT,
|
|
vco_feedback_scale << PLL_SYS_FBDIV_INT_FBDIV_INT_Pos,
|
|
PLL_SYS_FBDIV_INT_FBDIV_INT_Msk);
|
|
/* turn on the main power */
|
|
io_reg_atomic_clear(&pll->PWR, (1U << PLL_SYS_PWR_VCOPD_Pos)
|
|
| (1U << PLL_SYS_PWR_DSMPD_Pos)
|
|
| (1U << PLL_SYS_PWR_PD_Pos));
|
|
/* wait for VCO to lock (i.e. keep its output stable) */
|
|
while (!(pll->CS & PLL_SYS_CS_LOCK_Msk)) { }
|
|
/* set up post divisors and turn them on */
|
|
pll->PRIM = (post_div_1 << PLL_SYS_PRIM_POSTDIV1_Pos)
|
|
| (post_div_2 << PLL_SYS_PRIM_POSTDIV2_Pos);
|
|
io_reg_atomic_clear(&pll->PWR, 1U << PLL_SYS_PWR_POSTDIVPD_Pos);
|
|
}
|
|
|
|
/**
|
|
* @brief Stop the PLL for the system clock (@p pll = PLL_SYS) or
|
|
* the USB clock (@p pll = PLL_USB)
|
|
*/
|
|
static void _pll_stop(PLL_SYS_Type *pll)
|
|
{
|
|
uint32_t reg = (1U << PLL_SYS_PWR_VCOPD_Pos)
|
|
| (1U << PLL_SYS_PWR_POSTDIVPD_Pos)
|
|
| (1U << PLL_SYS_PWR_DSMPD_Pos)
|
|
| (1U << PLL_SYS_PWR_PD_Pos);
|
|
io_reg_atomic_set(&pll->PWR, reg);
|
|
}
|
|
|
|
void pll_start_sys(uint8_t ref_div,
|
|
uint16_t vco_feedback_scale,
|
|
uint8_t post_div_1, uint8_t post_div_2)
|
|
{
|
|
_pll_start(PLL_SYS, ref_div, vco_feedback_scale, post_div_1, post_div_2);
|
|
}
|
|
|
|
void pll_start_usb(uint8_t ref_div,
|
|
uint16_t vco_feedback_scale,
|
|
uint8_t post_div_1, uint8_t post_div_2)
|
|
{
|
|
_pll_start(PLL_USB, ref_div, vco_feedback_scale, post_div_1, post_div_2);
|
|
}
|
|
|
|
void pll_stop_sys(void)
|
|
{
|
|
_pll_stop(PLL_SYS);
|
|
}
|
|
|
|
void pll_stop_usb(void)
|
|
{
|
|
_pll_stop(PLL_USB);
|
|
}
|
|
|
|
/**
|
|
* @brief Reset the PLL of the system clock
|
|
*/
|
|
void pll_reset_sys(void)
|
|
{
|
|
periph_reset(1U << RESETS_RESET_pll_sys_Pos);
|
|
periph_reset_done(1U << RESETS_RESET_pll_sys_Pos);
|
|
}
|
|
|
|
/**
|
|
* @brief Reset the PLL of the USB clock
|
|
*/
|
|
void pll_reset_usb(void)
|
|
{
|
|
periph_reset(1U << RESETS_RESET_pll_usb_Pos);
|
|
periph_reset_done(1U << RESETS_RESET_pll_usb_Pos);
|
|
}
|