1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/rpx0xx/clock.c
Dylan Laduranty 9c5e508d2f cpu/rpx0xx: initialize USB PLL and ADC clock
Signed-off-by: Dylan Laduranty <dylan.laduranty@mesotic.com>
2023-04-25 21:12:42 +02:00

194 lines
8.0 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 CPU clock configuration
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
*
* @}
*/
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "vendor/RP2040.h"
#include "vendor/system_RP2040.h"
#include "io_reg.h"
#include "periph_cpu.h"
static void _clk_sys_set_source(CLOCKS_CLK_SYS_CTRL_SRC_Enum source)
{
io_reg_write_dont_corrupt(&CLOCKS->CLK_SYS_CTRL, source << CLOCKS_CLK_SYS_CTRL_SRC_Pos,
CLOCKS_CLK_SYS_CTRL_SRC_Msk);
}
static void _clk_sys_set_aux_source(CLOCKS_CLK_SYS_CTRL_AUXSRC_Enum source)
{
io_reg_write_dont_corrupt(&CLOCKS->CLK_SYS_CTRL, source << CLOCKS_CLK_SYS_CTRL_AUXSRC_Pos,
CLOCKS_CLK_SYS_CTRL_AUXSRC_Msk);
}
static void _clk_ref_set_source(CLOCKS_CLK_REF_CTRL_SRC_Enum source)
{
io_reg_write_dont_corrupt(&CLOCKS->CLK_REF_CTRL, source << CLOCKS_CLK_REF_CTRL_SRC_Pos,
CLOCKS_CLK_REF_CTRL_SRC_Msk);
}
static void _clk_ref_set_aux_source(CLOCKS_CLK_REF_CTRL_AUXSRC_Enum source)
{
io_reg_write_dont_corrupt(&CLOCKS->CLK_REF_CTRL, source << CLOCKS_CLK_REF_CTRL_AUXSRC_Pos,
CLOCKS_CLK_REF_CTRL_AUXSRC_Msk);
}
static void _gpout_set_aux_source(volatile uint32_t *reg, uint32_t value)
{
io_reg_write_dont_corrupt(reg,
value << CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_Pos,
CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_Msk);
}
void clock_sys_configure_source(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_SYS_CTRL_SRC_Enum source)
{
assert(f_out <= f_in);
assert(source != CLOCKS_CLK_SYS_CTRL_SRC_clksrc_clk_sys_aux);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_SYS_DIV_INT_Pos) / f_out;
/* switch the glitchless mux to clk_ref */
_clk_sys_set_source(source);
/* apply divider */
CLOCKS->CLK_SYS_DIV = div;
/* poll SELECTED until the switch is completed */
while (!(CLOCKS->CLK_SYS_SELECTED & (1U << source))) { }
}
void clock_sys_configure_aux_source(uint32_t f_in, uint32_t f_out,
CLOCKS_CLK_SYS_CTRL_AUXSRC_Enum aux)
{
assert(f_out <= f_in);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_SYS_DIV_INT_Pos) / f_out;
/* switch the glitchless mux to a source that is not the aux mux */
_clk_sys_set_source(CLOCKS_CLK_SYS_CTRL_SRC_clk_ref);
/* poll SELECTED until the switch is completed */
while (!(CLOCKS->CLK_SYS_SELECTED & (1U << CLOCKS_CLK_SYS_CTRL_SRC_clk_ref))) { }
/* change the auxiliary mux */
_clk_sys_set_aux_source(aux);
/* apply divider */
CLOCKS->CLK_SYS_DIV = div;
/* switch the glitchless mux to clk_sys_aux */
_clk_sys_set_source(CLOCKS_CLK_SYS_CTRL_SRC_clksrc_clk_sys_aux);
/* poll SELECTED until the switch is completed */
while (!(CLOCKS->CLK_SYS_SELECTED & (1U << CLOCKS_CLK_SYS_CTRL_SRC_clksrc_clk_sys_aux))) { }
}
void clock_ref_configure_source(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_REF_CTRL_SRC_Enum source)
{
assert(f_out <= f_in);
assert(source != CLOCKS_CLK_REF_CTRL_SRC_clksrc_clk_ref_aux);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_REF_DIV_INT_Pos) / f_out;
/* switch the glitchless mux to clock source */
_clk_ref_set_source(source);
/* apply divider */
CLOCKS->CLK_REF_DIV = div & CLOCKS_CLK_REF_DIV_INT_Msk;
/* poll SELECTED until the switch is completed */
while (!(CLOCKS->CLK_REF_SELECTED & (1U << source))) { }
}
void clock_ref_configure_aux_source(uint32_t f_in, uint32_t f_out,
CLOCKS_CLK_REF_CTRL_AUXSRC_Enum aux)
{
assert(f_out <= f_in);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_REF_DIV_INT_Pos) / f_out;
/* switch the glitchless mux to a source that is not the aux mux */
_clk_ref_set_source(CLOCKS_CLK_REF_CTRL_SRC_rosc_clksrc_ph);
/* poll SELECTED until the switch is completed */
while (!(CLOCKS->CLK_REF_SELECTED & (1U << CLOCKS_CLK_REF_CTRL_SRC_rosc_clksrc_ph))) { }
/* change the auxiliary mux */
_clk_ref_set_aux_source(aux);
/* apply divider */
CLOCKS->CLK_REF_DIV = div & CLOCKS_CLK_REF_DIV_INT_Msk;
/* switch the glitchless mux to clk_ref_aux */
_clk_ref_set_source(CLOCKS_CLK_REF_CTRL_SRC_clksrc_clk_ref_aux);
/* poll SELECTED until the switch is completed */
while (!(CLOCKS->CLK_REF_SELECTED & (1U << CLOCKS_CLK_REF_CTRL_SRC_clksrc_clk_ref_aux))) { }
}
void clock_periph_configure(CLOCKS_CLK_PERI_CTRL_AUXSRC_Enum aux)
{
io_reg_atomic_clear(&CLOCKS->CLK_PERI_CTRL, (1u << CLOCKS_CLK_PERI_CTRL_ENABLE_Pos));
io_reg_write_dont_corrupt(&CLOCKS->CLK_PERI_CTRL, aux << CLOCKS_CLK_PERI_CTRL_AUXSRC_Pos,
CLOCKS_CLK_PERI_CTRL_AUXSRC_Msk);
io_reg_atomic_set(&CLOCKS->CLK_PERI_CTRL, (1u << CLOCKS_CLK_PERI_CTRL_ENABLE_Pos));
}
void clock_gpout0_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_Enum aux)
{
assert(f_out <= f_in);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_REF_DIV_INT_Pos) / f_out;
io_reg_atomic_clear(&CLOCKS->CLK_GPOUT0_CTRL, 1U << CLOCKS_CLK_GPOUT0_CTRL_ENABLE_Pos);
_gpout_set_aux_source(&CLOCKS->CLK_GPOUT0_CTRL, aux);
CLOCKS->CLK_GPOUT0_DIV = div;
io_reg_atomic_set(&CLOCKS->CLK_GPOUT0_CTRL, 1U << CLOCKS_CLK_GPOUT0_CTRL_ENABLE_Pos);
io_reg_atomic_set(&PADS_BANK0->GPIO21, 1U << PADS_BANK0_GPIO21_IE_Pos);
gpio_set_function_select(21, FUNCTION_SELECT_CLOCK);
}
void clock_gpout1_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT1_CTRL_AUXSRC_Enum aux)
{
assert(f_out <= f_in);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_REF_DIV_INT_Pos) / f_out;
io_reg_atomic_clear(&CLOCKS->CLK_GPOUT1_CTRL, 1U << CLOCKS_CLK_GPOUT1_CTRL_ENABLE_Pos);
_gpout_set_aux_source(&CLOCKS->CLK_GPOUT1_CTRL, aux);
CLOCKS->CLK_GPOUT1_DIV = div;
io_reg_atomic_set(&CLOCKS->CLK_GPOUT1_CTRL, 1U << CLOCKS_CLK_GPOUT1_CTRL_ENABLE_Pos);
io_reg_atomic_set(&PADS_BANK0->GPIO23, 1U << PADS_BANK0_GPIO23_IE_Pos);
gpio_set_function_select(23, FUNCTION_SELECT_CLOCK);
}
void clock_gpout2_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT2_CTRL_AUXSRC_Enum aux)
{
assert(f_out <= f_in);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_REF_DIV_INT_Pos) / f_out;
io_reg_atomic_clear(&CLOCKS->CLK_GPOUT2_CTRL, 1U << CLOCKS_CLK_GPOUT2_CTRL_ENABLE_Pos);
_gpout_set_aux_source(&CLOCKS->CLK_GPOUT2_CTRL, aux);
CLOCKS->CLK_GPOUT2_DIV = div;
io_reg_atomic_set(&CLOCKS->CLK_GPOUT2_CTRL, 1U << CLOCKS_CLK_GPOUT2_CTRL_ENABLE_Pos);
io_reg_atomic_set(&PADS_BANK0->GPIO24, 1U << PADS_BANK0_GPIO24_IE_Pos);
gpio_set_function_select(24, FUNCTION_SELECT_CLOCK);
}
void clock_gpout3_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT3_CTRL_AUXSRC_Enum aux)
{
assert(f_out <= f_in);
uint32_t div = (((uint64_t)f_in) << CLOCKS_CLK_REF_DIV_INT_Pos) / f_out;
io_reg_atomic_clear(&CLOCKS->CLK_GPOUT3_CTRL, 1U << CLOCKS_CLK_GPOUT3_CTRL_ENABLE_Pos);
_gpout_set_aux_source(&CLOCKS->CLK_GPOUT3_CTRL, aux);
CLOCKS->CLK_GPOUT3_DIV = div;
io_reg_atomic_set(&CLOCKS->CLK_GPOUT3_CTRL, 1U << CLOCKS_CLK_GPOUT3_CTRL_ENABLE_Pos);
io_reg_atomic_set(&PADS_BANK0->GPIO25, 1U << PADS_BANK0_GPIO25_IE_Pos);
gpio_set_function_select(25, FUNCTION_SELECT_CLOCK);
}
void clock_adc_configure(CLOCKS_CLK_ADC_CTRL_AUXSRC_Enum aux)
{
/* Stop the clock generator */
io_reg_atomic_clear(&CLOCKS->CLK_ADC_CTRL,
(1u << CLOCKS_CLK_ADC_CTRL_ENABLE_Pos));
/* Selects the new auxiliary clock source */
io_reg_write_dont_corrupt(&CLOCKS->CLK_ADC_CTRL,
aux << CLOCKS_CLK_ADC_CTRL_AUXSRC_Pos,
CLOCKS_CLK_ADC_CTRL_AUXSRC_Msk);
/* Restart the clock generator */
io_reg_atomic_set(&CLOCKS->CLK_ADC_CTRL,
(1u << CLOCKS_CLK_ADC_CTRL_ENABLE_Pos));
}