mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-07 15:42:36 +00:00
Add support for SoC-specific clock ids and update the initialization function to support the existing RP2040 and add support for the RP2350. clock_control_rpi_pico.c uses numerical values for clock ids taken from rpi_pico_clock.h which are the "clock generator". For the RP2350 these values are different for some of the same logical clock sources, as well as the RP2040 and RP2350 having different clock sources available. Signed-off-by: Andrew Featherstone <andrew.featherstone@gmail.com>
969 lines
32 KiB
C
969 lines
32 KiB
C
/*
|
|
* Copyright (c) 2022 Andrei-Edward Popa
|
|
* Copyright (c) 2023 TOKITA Hiroshi
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT raspberrypi_pico_clock_controller
|
|
|
|
#include <zephyr/drivers/clock_control.h>
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
#include <zephyr/drivers/reset.h>
|
|
#if defined(CONFIG_SOC_SERIES_RP2040)
|
|
#include <zephyr/dt-bindings/clock/rpi_pico_rp2040_clock.h>
|
|
#else
|
|
#include <zephyr/dt-bindings/clock/rpi_pico_rp2350_clock.h>
|
|
#endif
|
|
|
|
#include <hardware/clocks.h>
|
|
#include <hardware/xosc.h>
|
|
#include <hardware/structs/rosc.h>
|
|
#include <hardware/pll.h>
|
|
#include <hardware/watchdog.h>
|
|
#include <hardware/resets.h>
|
|
|
|
/* Undefine to prevent conflicts with header definitions */
|
|
#undef pll_sys
|
|
#undef pll_usb
|
|
|
|
#define CTRL_SRC_LSB CLOCKS_CLK_REF_CTRL_SRC_LSB
|
|
#define CTRL_SRC_BITS CLOCKS_CLK_REF_CTRL_SRC_BITS
|
|
#define CTRL_AUXSRC_LSB CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_LSB
|
|
#define CTRL_AUXSRC_BITS CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_BITS
|
|
#define CTRL_ENABLE_BITS CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS
|
|
#define DIV_FRAC_BITS CLOCKS_CLK_GPOUT0_DIV_FRAC_BITS
|
|
#define DIV_INT_BITS CLOCKS_CLK_GPOUT0_DIV_INT_BITS
|
|
#define DIV_INT_LSB CLOCKS_CLK_GPOUT0_DIV_INT_LSB
|
|
|
|
#define PLL_VCO_FREQ_MIN 750000000
|
|
#define PLL_VCO_FREQ_MAX 1600000000
|
|
#define PLL_FB_DIV_MIN 16
|
|
#define PLL_FB_DIV_MAX 320
|
|
#define PLL_POST_DIV_MIN 1
|
|
#define PLL_POST_DIV_MAX 7
|
|
|
|
#define ROSC_PHASE_PASSWD_VALUE_PASS _u(0xAA)
|
|
|
|
#define STAGE_DS(n) \
|
|
(COND_CODE_1( \
|
|
DT_PROP_HAS_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), stage_drive_strength, n), \
|
|
(DT_PROP_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), stage_drive_strength, n) & \
|
|
ROSC_FREQA_DS0_BITS), \
|
|
(0)) \
|
|
<< (n * 3))
|
|
|
|
#define CLK_SRC_IS(clk, src) \
|
|
DT_SAME_NODE(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), 0), \
|
|
DT_INST_CLOCKS_CTLR_BY_NAME(0, src))
|
|
|
|
#define REF_DIV(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), clock_div)
|
|
#define FB_DIV(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), fb_div)
|
|
#define POST_DIV1(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), post_div1)
|
|
#define POST_DIV2(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), post_div2)
|
|
#define VCO_FREQ(pll) ((CLOCK_FREQ_xosc / REF_DIV(pll)) * FB_DIV(pll))
|
|
|
|
/*
|
|
* Using the 'clock-names[0]' for expanding macro to frequency value.
|
|
* The 'clock-names[0]' is set same as label value that given to the node itself.
|
|
* Use it for traverse clock tree to find root of clock source.
|
|
*/
|
|
#define CLOCK_FREQ(clk) _CONCAT(CLOCK_FREQ_, clk)
|
|
#define SRC_CLOCK(clk) DT_STRING_TOKEN_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), \
|
|
clock_names, 0)
|
|
#define SRC_CLOCK_FREQ(clk) _CONCAT(CLOCK_FREQ_, SRC_CLOCK(clk))
|
|
|
|
#define PLL_FREQ(pll) \
|
|
(DT_PROP(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), 0), clock_frequency) / \
|
|
REF_DIV(pll) * FB_DIV(pll) / POST_DIV1(pll) / POST_DIV2(pll))
|
|
|
|
#define CLOCK_FREQ_clk_gpout0 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout0), clock_frequency)
|
|
#define CLOCK_FREQ_clk_gpout1 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout1), clock_frequency)
|
|
#define CLOCK_FREQ_clk_gpout2 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout2), clock_frequency)
|
|
#define CLOCK_FREQ_clk_gpout3 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout3), clock_frequency)
|
|
#define CLOCK_FREQ_clk_hstx DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_hstx), clock_frequency)
|
|
#define CLOCK_FREQ_clk_ref DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_ref), clock_frequency)
|
|
#define CLOCK_FREQ_clk_sys DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_sys), clock_frequency)
|
|
#define CLOCK_FREQ_clk_usb DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_usb), clock_frequency)
|
|
#define CLOCK_FREQ_clk_adc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_adc), clock_frequency)
|
|
#define CLOCK_FREQ_clk_rtc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_rtc), clock_frequency)
|
|
#define CLOCK_FREQ_clk_peri DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_peri), clock_frequency)
|
|
#define CLOCK_FREQ_xosc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, xosc), clock_frequency)
|
|
#define CLOCK_FREQ_rosc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_frequency)
|
|
#define CLOCK_FREQ_rosc_ph DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_frequency)
|
|
#define CLOCK_FREQ_gpin0 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0), clock_frequency)
|
|
#define CLOCK_FREQ_gpin1 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1), clock_frequency)
|
|
#define CLOCK_FREQ_pll_sys PLL_FREQ(pll_sys)
|
|
#define CLOCK_FREQ_pll_usb PLL_FREQ(pll_usb)
|
|
|
|
#define CLOCK_AUX_SOURCE(clk) _CONCAT(_CONCAT(AUXSTEM_, clk), _CONCAT(AUXSRC_, SRC_CLOCK(clk)))
|
|
|
|
#define AUXSRC_xosc XOSC_CLKSRC
|
|
#define AUXSRC_rosc ROSC_CLKSRC
|
|
#define AUXSRC_rosc_ph ROSC_CLKSRC_PH
|
|
#define AUXSRC_pll_sys CLKSRC_PLL_SYS
|
|
#define AUXSRC_pll_usb CLKSRC_PLL_USB
|
|
#define AUXSRC_clk_ref CLK_REF
|
|
#define AUXSRC_clk_sys CLK_SYS
|
|
#define AUXSRC_clk_usb CLK_USB
|
|
#define AUXSRC_clk_adc CLK_ADC
|
|
#define AUXSRC_clk_gpin0 CLKSRC_GPIN0
|
|
#define AUXSRC_clk_gpin1 CLKSRC_GPIN1
|
|
#if defined(CONFIG_SOC_SERIES_RP2040)
|
|
#define AUXSRC_clk_rtc CLK_RTC
|
|
#else
|
|
#define AUXSRC_pll_usb_primary_ref_opcg CLKSRC_PLL_PLL_USB_PRIMARY_REF_OPCG
|
|
#define AUXSRC_lposc LPOSC_CLKSRC
|
|
#define AUXSRC_clk_hstx CLK_HSTX
|
|
#define AUXSRC_otp_clk2fc OTP_CLK2FC
|
|
#endif
|
|
|
|
#define AUXSTEM_clk_gpout0 CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_gpout1 CLOCKS_CLK_GPOUT1_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_gpout2 CLOCKS_CLK_GPOUT2_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_gpout3 CLOCKS_CLK_GPOUT3_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_ref CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_sys CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_usb CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_adc CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_
|
|
#define AUXSTEM_clk_peri CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_
|
|
#if defined(CONFIG_SOC_SERIES_RP2040)
|
|
#define AUXSTEM_clk_rtc CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_
|
|
#else
|
|
#define AUXSTEM_clk_hstx CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_
|
|
#endif
|
|
|
|
#define TUPLE_ENTRY(n, p, i) \
|
|
{ \
|
|
_CONCAT(RPI_PICO_CLKID_, DT_INST_STRING_UPPER_TOKEN_BY_IDX(0, clock_names, i)), \
|
|
COND_CODE_1( \
|
|
DT_PROP_HAS_IDX(DT_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(clocks), i), \
|
|
clocks, 0), \
|
|
(_CONCAT(RPI_PICO_CLKID_, \
|
|
DT_STRING_UPPER_TOKEN_BY_IDX( \
|
|
DT_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(clocks), i), \
|
|
clock_names, 0))), \
|
|
(-1)) \
|
|
}
|
|
|
|
enum rpi_pico_clkid {
|
|
rpi_pico_clkid_none = -1,
|
|
rpi_pico_clkid_clk_gpout0 = RPI_PICO_CLKID_CLK_GPOUT0,
|
|
rpi_pico_clkid_clk_gpout1 = RPI_PICO_CLKID_CLK_GPOUT1,
|
|
rpi_pico_clkid_clk_gpout2 = RPI_PICO_CLKID_CLK_GPOUT2,
|
|
rpi_pico_clkid_clk_gpout3 = RPI_PICO_CLKID_CLK_GPOUT3,
|
|
rpi_pico_clkid_clk_ref = RPI_PICO_CLKID_CLK_REF,
|
|
rpi_pico_clkid_clk_sys = RPI_PICO_CLKID_CLK_SYS,
|
|
rpi_pico_clkid_clk_peri = RPI_PICO_CLKID_CLK_PERI,
|
|
rpi_pico_clkid_clk_usb = RPI_PICO_CLKID_CLK_USB,
|
|
rpi_pico_clkid_clk_adc = RPI_PICO_CLKID_CLK_ADC,
|
|
#if defined(RPI_PICO_CLKID_CLK_RTC)
|
|
rpi_pico_clkid_clk_rtc = RPI_PICO_CLKID_CLK_RTC,
|
|
#endif
|
|
rpi_pico_clkid_pll_sys = RPI_PICO_CLKID_PLL_SYS,
|
|
rpi_pico_clkid_pll_usb = RPI_PICO_CLKID_PLL_USB,
|
|
rpi_pico_clkid_xosc = RPI_PICO_CLKID_XOSC,
|
|
rpi_pico_clkid_rosc = RPI_PICO_CLKID_ROSC,
|
|
rpi_pico_clkid_rosc_ph = RPI_PICO_CLKID_ROSC_PH,
|
|
rpi_pico_clkid_gpin0 = RPI_PICO_CLKID_GPIN0,
|
|
rpi_pico_clkid_gpin1 = RPI_PICO_CLKID_GPIN1,
|
|
END_OF_RPI_PICO_CLKID,
|
|
};
|
|
|
|
struct rpi_pico_clkid_tuple {
|
|
enum rpi_pico_clkid clk;
|
|
enum rpi_pico_clkid parent;
|
|
};
|
|
|
|
struct rpi_pico_clk_config {
|
|
uint32_t source;
|
|
uint32_t aux_source;
|
|
uint32_t rate;
|
|
uint32_t source_rate;
|
|
};
|
|
|
|
struct rpi_pico_pll_config {
|
|
uint32_t ref_div;
|
|
uint32_t fb_div;
|
|
uint32_t post_div1;
|
|
uint32_t post_div2;
|
|
};
|
|
|
|
struct rpi_pico_rosc_config {
|
|
uint32_t phase;
|
|
uint32_t range;
|
|
uint32_t div;
|
|
uint32_t code;
|
|
};
|
|
|
|
struct rpi_pico_gpin_config {
|
|
uint32_t frequency;
|
|
};
|
|
|
|
struct clock_control_rpi_pico_config {
|
|
clocks_hw_t *const clocks_regs;
|
|
xosc_hw_t *const xosc_regs;
|
|
pll_hw_t *const pll_sys_regs;
|
|
pll_hw_t *const pll_usb_regs;
|
|
rosc_hw_t *const rosc_regs;
|
|
const struct pinctrl_dev_config *pcfg;
|
|
struct rpi_pico_pll_config plls_data[RPI_PICO_PLL_COUNT];
|
|
struct rpi_pico_clk_config clocks_data[RPI_PICO_CLOCK_COUNT];
|
|
struct rpi_pico_rosc_config rosc_data;
|
|
struct rpi_pico_gpin_config gpin_data[RPI_PICO_GPIN_COUNT];
|
|
};
|
|
|
|
struct clock_control_rpi_pico_data {
|
|
uint32_t rosc_freq;
|
|
uint32_t rosc_ph_freq;
|
|
};
|
|
|
|
uint64_t rpi_pico_frequency_count(const struct device *dev, clock_control_subsys_t sys)
|
|
{
|
|
const struct clock_control_rpi_pico_config *config = dev->config;
|
|
enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys;
|
|
fc_hw_t *fc0 = &config->clocks_regs->fc0;
|
|
uint32_t fc0_id;
|
|
|
|
switch (clkid) {
|
|
case rpi_pico_clkid_clk_ref:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_REF;
|
|
break;
|
|
case rpi_pico_clkid_clk_sys:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_SYS;
|
|
break;
|
|
case rpi_pico_clkid_clk_peri:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_PERI;
|
|
break;
|
|
case rpi_pico_clkid_clk_usb:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_USB;
|
|
break;
|
|
case rpi_pico_clkid_clk_adc:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_ADC;
|
|
break;
|
|
#if defined(CONFIG_SOC_SERIES_RP2040)
|
|
case rpi_pico_clkid_clk_rtc:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_RTC;
|
|
break;
|
|
#endif
|
|
case rpi_pico_clkid_pll_sys:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY;
|
|
break;
|
|
case rpi_pico_clkid_pll_usb:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY;
|
|
break;
|
|
case rpi_pico_clkid_xosc:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_XOSC_CLKSRC;
|
|
break;
|
|
case rpi_pico_clkid_rosc:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC;
|
|
break;
|
|
case rpi_pico_clkid_rosc_ph:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC_PH;
|
|
break;
|
|
case rpi_pico_clkid_gpin0:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0;
|
|
break;
|
|
case rpi_pico_clkid_gpin1:
|
|
fc0_id = CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
(void)frequency_count_khz(fc0_id);
|
|
|
|
return ((fc0->result >> CLOCKS_FC0_RESULT_KHZ_LSB) * 1000) +
|
|
((fc0->result & CLOCKS_FC0_RESULT_FRAC_BITS) * 1000 / CLOCKS_FC0_RESULT_FRAC_BITS);
|
|
}
|
|
|
|
static int rpi_pico_rosc_write(const struct device *dev, io_rw_32 *addr, uint32_t value)
|
|
{
|
|
hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS);
|
|
|
|
if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
*addr = value;
|
|
|
|
if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get source clock id of this clock
|
|
*
|
|
* @param dev pointer to clock device
|
|
* @param id id of this clock
|
|
* @return parent clock id
|
|
*/
|
|
static enum rpi_pico_clkid rpi_pico_get_clock_src(const struct device *dev, enum rpi_pico_clkid id)
|
|
{
|
|
const struct clock_control_rpi_pico_config *config = dev->config;
|
|
enum rpi_pico_clkid srcid;
|
|
|
|
switch (id) {
|
|
case rpi_pico_clkid_clk_gpout0:
|
|
case rpi_pico_clkid_clk_gpout1:
|
|
case rpi_pico_clkid_clk_gpout2:
|
|
case rpi_pico_clkid_clk_gpout3: {
|
|
const static enum rpi_pico_clkid table[] = {
|
|
rpi_pico_clkid_pll_sys,
|
|
rpi_pico_clkid_gpin0,
|
|
rpi_pico_clkid_gpin1,
|
|
rpi_pico_clkid_pll_usb,
|
|
rpi_pico_clkid_rosc_ph,
|
|
rpi_pico_clkid_xosc,
|
|
rpi_pico_clkid_clk_sys,
|
|
rpi_pico_clkid_clk_usb,
|
|
rpi_pico_clkid_clk_adc,
|
|
#if defined(CONFIG_SOC_SERIES_RP2040)
|
|
rpi_pico_clkid_clk_rtc,
|
|
#endif
|
|
rpi_pico_clkid_clk_ref,
|
|
};
|
|
|
|
clock_hw_t *clock_hw = &config->clocks_regs->clk[id];
|
|
uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB);
|
|
|
|
srcid = table[aux];
|
|
break;
|
|
}
|
|
case rpi_pico_clkid_clk_ref: {
|
|
const static enum rpi_pico_clkid table[] = {
|
|
rpi_pico_clkid_pll_usb,
|
|
rpi_pico_clkid_gpin0,
|
|
rpi_pico_clkid_gpin1,
|
|
};
|
|
|
|
clock_hw_t *clock_hw = &clocks_hw->clk[id];
|
|
uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB);
|
|
uint32_t src = ((clock_hw->ctrl >> CTRL_SRC_LSB) & CTRL_SRC_BITS);
|
|
|
|
if (src == CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH) {
|
|
srcid = rpi_pico_clkid_rosc_ph;
|
|
} else if (src == CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC) {
|
|
srcid = rpi_pico_clkid_xosc;
|
|
} else {
|
|
srcid = table[aux];
|
|
}
|
|
break;
|
|
}
|
|
case rpi_pico_clkid_clk_sys: {
|
|
const static enum rpi_pico_clkid table[] = {
|
|
rpi_pico_clkid_pll_sys,
|
|
rpi_pico_clkid_pll_usb,
|
|
rpi_pico_clkid_rosc,
|
|
rpi_pico_clkid_xosc,
|
|
rpi_pico_clkid_gpin0,
|
|
rpi_pico_clkid_gpin1,
|
|
};
|
|
|
|
clock_hw_t *clock_hw = &clocks_hw->clk[id];
|
|
uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB);
|
|
uint32_t src = ((clock_hw->ctrl >> CTRL_SRC_LSB) & CTRL_SRC_BITS);
|
|
|
|
if (src == CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF) {
|
|
srcid = rpi_pico_clkid_clk_ref;
|
|
} else {
|
|
srcid = table[aux];
|
|
}
|
|
break;
|
|
}
|
|
case rpi_pico_clkid_clk_peri: {
|
|
const static enum rpi_pico_clkid table[] = {
|
|
rpi_pico_clkid_clk_sys,
|
|
rpi_pico_clkid_pll_sys,
|
|
rpi_pico_clkid_pll_usb,
|
|
rpi_pico_clkid_rosc_ph,
|
|
rpi_pico_clkid_xosc,
|
|
rpi_pico_clkid_gpin0,
|
|
rpi_pico_clkid_gpin1,
|
|
};
|
|
|
|
clock_hw_t *clock_hw = &clocks_hw->clk[id];
|
|
uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB);
|
|
|
|
srcid = table[aux];
|
|
break;
|
|
}
|
|
case rpi_pico_clkid_clk_usb:
|
|
case rpi_pico_clkid_clk_adc:
|
|
#if defined(RPI_PICO_CLKID_CLK_RTC)
|
|
case rpi_pico_clkid_clk_rtc:
|
|
#else
|
|
|
|
#endif
|
|
{
|
|
const static enum rpi_pico_clkid table[] = {
|
|
rpi_pico_clkid_pll_usb,
|
|
rpi_pico_clkid_pll_sys,
|
|
rpi_pico_clkid_rosc_ph,
|
|
rpi_pico_clkid_xosc,
|
|
rpi_pico_clkid_gpin0,
|
|
rpi_pico_clkid_gpin1,
|
|
};
|
|
|
|
clock_hw_t *clock_hw = &clocks_hw->clk[id];
|
|
uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB);
|
|
|
|
srcid = table[aux];
|
|
break;
|
|
}
|
|
case rpi_pico_clkid_pll_sys:
|
|
case rpi_pico_clkid_pll_usb: {
|
|
srcid = rpi_pico_clkid_xosc;
|
|
break;
|
|
}
|
|
default:
|
|
srcid = rpi_pico_clkid_none;
|
|
break;
|
|
}
|
|
|
|
return srcid;
|
|
}
|
|
|
|
/**
|
|
* Query clock is enabled or not
|
|
*
|
|
* @param dev pointer to clock device
|
|
* @param id id of clock
|
|
* @return true if the clock enabled, otherwith false
|
|
*/
|
|
static bool rpi_pico_is_clock_enabled(const struct device *dev, enum rpi_pico_clkid id)
|
|
{
|
|
const struct clock_control_rpi_pico_config *config = dev->config;
|
|
|
|
if (id == rpi_pico_clkid_clk_sys || id == rpi_pico_clkid_clk_ref) {
|
|
return true;
|
|
} else if (id == rpi_pico_clkid_clk_usb ||
|
|
id == rpi_pico_clkid_clk_peri ||
|
|
id == rpi_pico_clkid_clk_adc ||
|
|
#if defined(RPI_PICO_CLKID_CLK_RTC)
|
|
id == rpi_pico_clkid_clk_rtc ||
|
|
#endif
|
|
id == rpi_pico_clkid_clk_gpout0 ||
|
|
id == rpi_pico_clkid_clk_gpout1 ||
|
|
id == rpi_pico_clkid_clk_gpout2 ||
|
|
id == rpi_pico_clkid_clk_gpout3) {
|
|
clock_hw_t *clock_hw = &config->clocks_regs->clk[id];
|
|
|
|
if (clock_hw->ctrl & CTRL_ENABLE_BITS) {
|
|
return true;
|
|
}
|
|
} else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) {
|
|
pll_hw_t *pll = (id == rpi_pico_clkid_pll_sys) ? config->pll_sys_regs
|
|
: config->pll_usb_regs;
|
|
|
|
if (!(pll->pwr & (PLL_PWR_VCOPD_BITS | PLL_PWR_POSTDIVPD_BITS | PLL_PWR_PD_BITS))) {
|
|
return true;
|
|
}
|
|
} else if (id == rpi_pico_clkid_xosc) {
|
|
if (config->xosc_regs->status & XOSC_STATUS_ENABLED_BITS) {
|
|
return true;
|
|
}
|
|
} else if (id == rpi_pico_clkid_rosc || id == rpi_pico_clkid_rosc_ph) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Calculate clock frequency with traversing clock tree.
|
|
*
|
|
* @param dev pointer to clock device
|
|
* @param id id of clock
|
|
* @return frequency value or 0 if disabled
|
|
*/
|
|
static float rpi_pico_calc_clock_freq(const struct device *dev, enum rpi_pico_clkid id)
|
|
{
|
|
const struct clock_control_rpi_pico_config *config = dev->config;
|
|
struct clock_control_rpi_pico_data *data = dev->data;
|
|
float freq = 0.f;
|
|
|
|
if (!rpi_pico_is_clock_enabled(dev, id)) {
|
|
return freq;
|
|
}
|
|
|
|
if (id == rpi_pico_clkid_clk_sys ||
|
|
id == rpi_pico_clkid_clk_usb ||
|
|
id == rpi_pico_clkid_clk_adc ||
|
|
#if defined(RPI_PICO_CLKID_CLK_RTC)
|
|
id == rpi_pico_clkid_clk_rtc ||
|
|
#endif
|
|
id == rpi_pico_clkid_clk_ref ||
|
|
id == rpi_pico_clkid_clk_gpout0 ||
|
|
id == rpi_pico_clkid_clk_gpout1 ||
|
|
id == rpi_pico_clkid_clk_gpout2 ||
|
|
id == rpi_pico_clkid_clk_gpout3) {
|
|
clock_hw_t *clock_hw = &config->clocks_regs->clk[id];
|
|
|
|
freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)) /
|
|
(((clock_hw->div & DIV_INT_BITS) >> DIV_INT_LSB) +
|
|
((clock_hw->div & DIV_FRAC_BITS) / (float)DIV_FRAC_BITS));
|
|
} else if (id == rpi_pico_clkid_clk_peri) {
|
|
freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id));
|
|
} else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) {
|
|
pll_hw_t *pll = (id == rpi_pico_clkid_pll_sys) ? config->pll_sys_regs
|
|
: config->pll_usb_regs;
|
|
freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)) *
|
|
(pll->fbdiv_int) / (pll->cs & PLL_CS_REFDIV_BITS) /
|
|
((pll->prim & PLL_PRIM_POSTDIV1_BITS) >> PLL_PRIM_POSTDIV1_LSB) /
|
|
((pll->prim & PLL_PRIM_POSTDIV2_BITS) >> PLL_PRIM_POSTDIV2_LSB);
|
|
} else if (id == rpi_pico_clkid_xosc) {
|
|
freq = CLOCK_FREQ_xosc;
|
|
} else if (id == rpi_pico_clkid_rosc) {
|
|
freq = data->rosc_freq;
|
|
} else if (id == rpi_pico_clkid_rosc_ph) {
|
|
freq = data->rosc_ph_freq;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
static int rpi_pico_is_valid_clock_index(enum rpi_pico_clkid index)
|
|
{
|
|
if (index >= END_OF_RPI_PICO_CLKID) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int clock_control_rpi_pico_on(const struct device *dev, clock_control_subsys_t sys)
|
|
{
|
|
const struct clock_control_rpi_pico_config *config = dev->config;
|
|
enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys;
|
|
|
|
if (rpi_pico_is_valid_clock_index(clkid) < 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (clkid) {
|
|
case rpi_pico_clkid_pll_sys:
|
|
hw_clear_bits(&config->pll_sys_regs->pwr, PLL_PWR_BITS);
|
|
break;
|
|
case rpi_pico_clkid_pll_usb:
|
|
hw_clear_bits(&config->pll_usb_regs->pwr, PLL_PWR_BITS);
|
|
break;
|
|
default:
|
|
hw_set_bits(&config->clocks_regs->clk[clkid].ctrl, CTRL_ENABLE_BITS);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int clock_control_rpi_pico_off(const struct device *dev, clock_control_subsys_t sys)
|
|
{
|
|
const struct clock_control_rpi_pico_config *config = dev->config;
|
|
enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys;
|
|
|
|
if (rpi_pico_is_valid_clock_index(clkid) < 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (clkid) {
|
|
case rpi_pico_clkid_pll_sys:
|
|
hw_set_bits(&config->pll_sys_regs->pwr, PLL_PWR_BITS);
|
|
break;
|
|
case rpi_pico_clkid_pll_usb:
|
|
hw_set_bits(&config->pll_usb_regs->pwr, PLL_PWR_BITS);
|
|
break;
|
|
default:
|
|
hw_clear_bits(&config->clocks_regs->clk[clkid].ctrl, CTRL_ENABLE_BITS);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static enum clock_control_status clock_control_rpi_pico_get_status(const struct device *dev,
|
|
clock_control_subsys_t sys)
|
|
{
|
|
enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys;
|
|
|
|
if (rpi_pico_is_valid_clock_index(clkid) < 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (rpi_pico_is_clock_enabled(dev, clkid)) {
|
|
return CLOCK_CONTROL_STATUS_ON;
|
|
}
|
|
|
|
return CLOCK_CONTROL_STATUS_OFF;
|
|
}
|
|
|
|
static int clock_control_rpi_pico_get_rate(const struct device *dev, clock_control_subsys_t sys,
|
|
uint32_t *rate)
|
|
{
|
|
struct clock_control_rpi_pico_data *data = dev->data;
|
|
enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys;
|
|
|
|
if (rpi_pico_is_valid_clock_index(clkid) < 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_RPI_PICO_ROSC_USE_MEASURED_FREQ)) {
|
|
if (clkid == rpi_pico_clkid_rosc) {
|
|
data->rosc_freq = rpi_pico_frequency_count(dev, sys);
|
|
} else if (clkid == rpi_pico_clkid_rosc_ph) {
|
|
data->rosc_ph_freq = rpi_pico_frequency_count(dev, sys);
|
|
}
|
|
}
|
|
|
|
*rate = (int)rpi_pico_calc_clock_freq(dev, clkid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void rpi_pico_clkid_tuple_swap(struct rpi_pico_clkid_tuple *lhs, struct rpi_pico_clkid_tuple *rhs)
|
|
{
|
|
struct rpi_pico_clkid_tuple tmp = *lhs;
|
|
*lhs = *rhs;
|
|
*rhs = tmp;
|
|
}
|
|
|
|
void rpi_pico_clkid_tuple_reorder_by_dependencies(struct rpi_pico_clkid_tuple *tuples, size_t len)
|
|
{
|
|
uint32_t sorted_idx = 0;
|
|
uint32_t checked_idx = 0;
|
|
uint32_t target = -1;
|
|
|
|
while (sorted_idx < len) {
|
|
for (uint32_t i = sorted_idx; i < len; i++) {
|
|
if (tuples[i].parent == target) {
|
|
rpi_pico_clkid_tuple_swap(&tuples[sorted_idx], &tuples[i]);
|
|
sorted_idx++;
|
|
}
|
|
}
|
|
target = tuples[checked_idx++].clk;
|
|
}
|
|
}
|
|
|
|
static int clock_control_rpi_pico_init(const struct device *dev)
|
|
{
|
|
const struct clock_control_rpi_pico_config *config = dev->config;
|
|
struct clock_control_rpi_pico_data *data = dev->data;
|
|
clocks_hw_t *clocks_regs = config->clocks_regs;
|
|
rosc_hw_t *rosc_regs = config->rosc_regs;
|
|
pll_hw_t *plls[] = {config->pll_sys_regs, config->pll_usb_regs};
|
|
struct rpi_pico_clkid_tuple tuples[] = {
|
|
DT_INST_FOREACH_PROP_ELEM_SEP(0, clock_names, TUPLE_ENTRY, (,))};
|
|
uint32_t rosc_div;
|
|
int ret;
|
|
|
|
/* Reset all function before clock configuring */
|
|
reset_block(~(RESETS_RESET_IO_QSPI_BITS | RESETS_RESET_PADS_QSPI_BITS |
|
|
RESETS_RESET_PLL_USB_BITS | RESETS_RESET_USBCTRL_BITS |
|
|
RESETS_RESET_SYSCFG_BITS | RESETS_RESET_PLL_SYS_BITS));
|
|
|
|
unreset_block_wait(RESETS_RESET_BITS &
|
|
~(RESETS_RESET_ADC_BITS |
|
|
#if defined(RESETS_RESET_RTC_BITS)
|
|
RESETS_RESET_RTC_BITS |
|
|
#endif
|
|
#if defined(RESETS_RESET_HSTX_BITS)
|
|
RESETS_RESET_HSTX_BITS |
|
|
#endif
|
|
RESETS_RESET_SPI0_BITS | RESETS_RESET_SPI1_BITS |
|
|
RESETS_RESET_UART0_BITS | RESETS_RESET_UART1_BITS |
|
|
RESETS_RESET_USBCTRL_BITS));
|
|
|
|
/* Start tick in watchdog */
|
|
watchdog_start_tick(CLOCK_FREQ_xosc / 1000000);
|
|
|
|
clocks_regs->resus.ctrl = 0;
|
|
|
|
/* Configure xosc */
|
|
xosc_init();
|
|
|
|
/* Before we touch PLLs, switch sys and ref cleanly away from their aux sources. */
|
|
clocks_hw->clk[RPI_PICO_CLKID_CLK_SYS].ctrl &= ~CTRL_SRC_BITS;
|
|
while (clocks_hw->clk[RPI_PICO_CLKID_CLK_SYS].selected != 0x1) {
|
|
;
|
|
}
|
|
clocks_hw->clk[RPI_PICO_CLKID_CLK_REF].ctrl &= ~CTRL_SRC_BITS;
|
|
while (clocks_hw->clk[RPI_PICO_CLKID_CLK_REF].selected != 0x1) {
|
|
;
|
|
}
|
|
|
|
/* Configure pll */
|
|
for (uint32_t i = 0; i < RPI_PICO_PLL_COUNT; i++) {
|
|
pll_init(plls[i], config->plls_data[i].ref_div,
|
|
CLOCK_FREQ_xosc * config->plls_data[i].fb_div,
|
|
config->plls_data[i].post_div1, config->plls_data[i].post_div2);
|
|
}
|
|
|
|
/* Configure clocks */
|
|
rpi_pico_clkid_tuple_reorder_by_dependencies(tuples, ARRAY_SIZE(tuples));
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(tuples); i++) {
|
|
if (tuples[i].clk < 0 || tuples[i].clk >= RPI_PICO_CLOCK_COUNT) {
|
|
continue;
|
|
}
|
|
|
|
if (!(clock_configure(tuples[i].clk, config->clocks_data[tuples[i].clk].source,
|
|
config->clocks_data[tuples[i].clk].aux_source,
|
|
config->clocks_data[tuples[i].clk].source_rate,
|
|
config->clocks_data[tuples[i].clk].rate))) {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout0].ctrl, CTRL_ENABLE_BITS);
|
|
hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout1].ctrl, CTRL_ENABLE_BITS);
|
|
hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout2].ctrl, CTRL_ENABLE_BITS);
|
|
hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout3].ctrl, CTRL_ENABLE_BITS);
|
|
|
|
/* Configure rosc */
|
|
ret = rpi_pico_rosc_write(dev, &rosc_regs->phase,
|
|
(ROSC_PHASE_PASSWD_VALUE_PASS << ROSC_PHASE_PASSWD_LSB) |
|
|
config->rosc_data.phase);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = rpi_pico_rosc_write(dev, &rosc_regs->ctrl,
|
|
(ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB) |
|
|
config->rosc_data.range);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (config->rosc_data.div <= 0) {
|
|
rosc_div = ROSC_DIV_VALUE_PASS + 1;
|
|
} else if (config->rosc_data.div > 31) {
|
|
rosc_div = ROSC_DIV_VALUE_PASS;
|
|
} else {
|
|
rosc_div = ROSC_DIV_VALUE_PASS + config->rosc_data.div;
|
|
}
|
|
|
|
ret = rpi_pico_rosc_write(dev, &rosc_regs->div, rosc_div);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = rpi_pico_rosc_write(dev, &rosc_regs->freqa,
|
|
(ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) |
|
|
(config->rosc_data.code & UINT16_MAX));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = rpi_pico_rosc_write(dev, &rosc_regs->freqb,
|
|
(ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) |
|
|
(config->rosc_data.code >> 16));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
unreset_block_wait(RESETS_RESET_BITS);
|
|
|
|
if (IS_ENABLED(CONFIG_RPI_PICO_ROSC_USE_MEASURED_FREQ)) {
|
|
data->rosc_freq =
|
|
rpi_pico_frequency_count(dev, (clock_control_subsys_t)rpi_pico_clkid_rosc);
|
|
data->rosc_ph_freq = rpi_pico_frequency_count(
|
|
dev, (clock_control_subsys_t)rpi_pico_clkid_rosc_ph);
|
|
}
|
|
|
|
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
|
|
if (ret < 0 && ret != -ENOENT) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static DEVICE_API(clock_control, clock_control_rpi_pico_api) = {
|
|
.on = clock_control_rpi_pico_on,
|
|
.off = clock_control_rpi_pico_off,
|
|
.get_rate = clock_control_rpi_pico_get_rate,
|
|
.get_status = clock_control_rpi_pico_get_status,
|
|
};
|
|
|
|
BUILD_ASSERT((VCO_FREQ(pll_sys) >= PLL_VCO_FREQ_MIN) && (VCO_FREQ(pll_sys) <= PLL_VCO_FREQ_MAX) &&
|
|
(VCO_FREQ(pll_sys) >= (CLOCK_FREQ_xosc / REF_DIV(pll_sys) * 16)),
|
|
"pll_sys: vco_freq is out of range");
|
|
BUILD_ASSERT((FB_DIV(pll_sys) >= PLL_FB_DIV_MIN) && (FB_DIV(pll_sys) <= PLL_FB_DIV_MAX),
|
|
"pll_sys: fb-div is out of range");
|
|
BUILD_ASSERT((POST_DIV1(pll_sys) >= PLL_POST_DIV_MIN) && (POST_DIV1(pll_sys) <= PLL_POST_DIV_MAX),
|
|
"pll_sys: post-div1 is out of range");
|
|
BUILD_ASSERT((POST_DIV2(pll_sys) >= PLL_POST_DIV_MIN) && (POST_DIV2(pll_sys) <= PLL_POST_DIV_MAX),
|
|
"pll_sys: post-div2 is out of range");
|
|
|
|
BUILD_ASSERT((VCO_FREQ(pll_usb) >= PLL_VCO_FREQ_MIN) && (VCO_FREQ(pll_usb) <= PLL_VCO_FREQ_MAX) &&
|
|
(VCO_FREQ(pll_usb) >= (CLOCK_FREQ_xosc / REF_DIV(pll_usb) * 16)),
|
|
"pll_usb: vco_freq is out of range");
|
|
BUILD_ASSERT((FB_DIV(pll_usb) >= PLL_FB_DIV_MIN) && (FB_DIV(pll_usb) <= PLL_FB_DIV_MAX),
|
|
"pll_usb: fb-div is out of range");
|
|
BUILD_ASSERT((POST_DIV1(pll_usb) >= PLL_POST_DIV_MIN) && (POST_DIV1(pll_usb) <= PLL_POST_DIV_MAX),
|
|
"pll_usb: post-div is out of range");
|
|
BUILD_ASSERT((POST_DIV2(pll_usb) >= PLL_POST_DIV_MIN) && (POST_DIV2(pll_usb) <= PLL_POST_DIV_MAX),
|
|
"pll_usb: post-div is out of range");
|
|
|
|
BUILD_ASSERT(SRC_CLOCK_FREQ(clk_ref) >= CLOCK_FREQ_clk_ref,
|
|
"clk_ref: clock divider is out of range");
|
|
BUILD_ASSERT(SRC_CLOCK_FREQ(clk_sys) >= CLOCK_FREQ_clk_sys,
|
|
"clk_sys: clock divider is out of range");
|
|
BUILD_ASSERT(SRC_CLOCK_FREQ(clk_usb) >= CLOCK_FREQ_clk_usb,
|
|
"clk_usb: clock divider is out of range");
|
|
BUILD_ASSERT(SRC_CLOCK_FREQ(clk_adc) >= CLOCK_FREQ_clk_adc,
|
|
"clk_adc: clock divider is out of range");
|
|
#if defined(CONFIG_SOC_SERIES_RP2040)
|
|
BUILD_ASSERT(SRC_CLOCK_FREQ(clk_rtc) >= CLOCK_FREQ_clk_rtc,
|
|
"clk_rtc: clock divider is out of range");
|
|
#endif
|
|
BUILD_ASSERT(SRC_CLOCK_FREQ(clk_peri) >= CLOCK_FREQ_clk_peri,
|
|
"clk_peri: clock divider is out of range");
|
|
|
|
BUILD_ASSERT(CLOCK_FREQ(rosc_ph) == CLOCK_FREQ(rosc), "rosc_ph: frequency must be equal to rosc");
|
|
|
|
PINCTRL_DT_INST_DEFINE(0);
|
|
|
|
static const struct clock_control_rpi_pico_config clock_control_rpi_pico_config = {
|
|
.clocks_regs = (clocks_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, clocks),
|
|
.xosc_regs = (xosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, xosc),
|
|
.pll_sys_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_sys),
|
|
.pll_usb_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_usb),
|
|
.rosc_regs = (rosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, rosc),
|
|
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
|
|
.clocks_data = {
|
|
[RPI_PICO_CLKID_CLK_GPOUT0] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_gpout0),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_gpout0),
|
|
.rate = CLOCK_FREQ(clk_gpout0),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_GPOUT1] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_gpout1),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_gpout1),
|
|
.rate = CLOCK_FREQ(clk_gpout1),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_GPOUT2] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_gpout2),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_gpout2),
|
|
.rate = CLOCK_FREQ(clk_gpout2),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_GPOUT3] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_gpout3),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_gpout3),
|
|
.rate = CLOCK_FREQ(clk_gpout3),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_REF] = {
|
|
#if CLK_SRC_IS(clk_ref, rosc_ph)
|
|
.source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH,
|
|
.aux_source = 0,
|
|
#elif CLK_SRC_IS(clk_ref, xosc)
|
|
.source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
|
|
.aux_source = 0,
|
|
#else
|
|
.source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX,
|
|
#endif
|
|
.source_rate = SRC_CLOCK_FREQ(clk_ref),
|
|
.rate = CLOCK_FREQ(clk_ref),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_SYS] = {
|
|
#if CLK_SRC_IS(clk_sys, clk_ref)
|
|
.source = CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,
|
|
.aux_source = 0,
|
|
#else
|
|
.source = CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_sys),
|
|
#endif
|
|
.source_rate = SRC_CLOCK_FREQ(clk_sys),
|
|
.rate = CLOCK_FREQ(clk_sys),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_PERI] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_peri),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_peri),
|
|
.rate = CLOCK_FREQ(clk_peri),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_USB] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_usb),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_usb),
|
|
.rate = CLOCK_FREQ(clk_usb),
|
|
},
|
|
[RPI_PICO_CLKID_CLK_ADC] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_adc),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_adc),
|
|
.rate = CLOCK_FREQ(clk_adc),
|
|
},
|
|
#if defined(RPI_PICO_CLKID_CLK_RTC)
|
|
[RPI_PICO_CLKID_CLK_RTC] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_rtc),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_rtc),
|
|
.rate = CLOCK_FREQ(clk_rtc),
|
|
},
|
|
#elif defined(RPI_PICO_CLKID_CLK_HSTX)
|
|
[RPI_PICO_CLKID_CLK_HSTX] = {
|
|
.source = 0,
|
|
.aux_source = CLOCK_AUX_SOURCE(clk_hstx),
|
|
.source_rate = SRC_CLOCK_FREQ(clk_hstx),
|
|
.rate = CLOCK_FREQ(clk_hstx),
|
|
},
|
|
#endif
|
|
},
|
|
.plls_data = {
|
|
[RPI_PICO_PLL_SYS] = {
|
|
.ref_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), clock_div),
|
|
.fb_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), fb_div),
|
|
.post_div1 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), post_div1),
|
|
.post_div2 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), post_div2),
|
|
},
|
|
[RPI_PICO_PLL_USB] = {
|
|
.ref_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), clock_div),
|
|
.fb_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), fb_div),
|
|
.post_div1 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), post_div1),
|
|
.post_div2 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), post_div2),
|
|
},
|
|
},
|
|
.rosc_data = {
|
|
.phase = (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc),
|
|
phase_flip),
|
|
(ROSC_PHASE_FLIP_BITS), (0x0)) |
|
|
COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc),
|
|
phase),
|
|
((DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), phase) &
|
|
ROSC_PHASE_SHIFT_BITS) | ROSC_PHASE_ENABLE_BITS), (0x0))),
|
|
.div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_div),
|
|
.range = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), range),
|
|
.code = (STAGE_DS(0) | STAGE_DS(1) | STAGE_DS(2) | STAGE_DS(3) |
|
|
STAGE_DS(4) | STAGE_DS(5) | STAGE_DS(6) | STAGE_DS(7)),
|
|
},
|
|
.gpin_data = {
|
|
[RPI_PICO_GPIN_0] = {
|
|
COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0),
|
|
clock_frequency),
|
|
(.frequency = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0),
|
|
clock_frequency),),
|
|
(.frequency = 0,))
|
|
},
|
|
[RPI_PICO_GPIN_1] = {
|
|
COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1),
|
|
clock_frequency),
|
|
(.frequency = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1),
|
|
clock_frequency),),
|
|
(.frequency = 0,))
|
|
},
|
|
},
|
|
};
|
|
|
|
static struct clock_control_rpi_pico_data clock_control_rpi_pico_data = {
|
|
.rosc_freq = CLOCK_FREQ(rosc),
|
|
.rosc_ph_freq = CLOCK_FREQ(rosc_ph),
|
|
};
|
|
|
|
DEVICE_DT_INST_DEFINE(0, clock_control_rpi_pico_init, NULL, &clock_control_rpi_pico_data,
|
|
&clock_control_rpi_pico_config, PRE_KERNEL_1,
|
|
CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_rpi_pico_api);
|