drivers: clock_control: Added clock driver for Raspberry Pi Pico

Added clock driver for Raspberry Pi Pico platform

Signed-off-by: Andrei-Edward Popa <andrei.popa105@yahoo.com>
Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
This commit is contained in:
Andrei-Edward Popa 2023-03-18 22:59:40 +02:00 committed by Carles Cufí
parent 0bc8de8444
commit ea1cafbee7
20 changed files with 1243 additions and 63 deletions

View file

@ -25,12 +25,6 @@
aliases {
watchdog0 = &wdt0;
};
xtal_clk: xtal-clk {
compatible = "fixed-clock";
clock-frequency = <12000000>;
#clock-cells = <0>;
};
};
&flash0 {

View file

@ -17,6 +17,9 @@ CONFIG_UART_CONSOLE=y
# Enable reset by default
CONFIG_RESET=y
# Enable clock control by default
CONFIG_CLOCK_CONTROL=y
# Code partition needed to target the correct flash range
CONFIG_USE_DT_CODE_PARTITION=y

View file

@ -23,12 +23,6 @@
zephyr,code-partition = &code_partition;
};
xtal_clk: xtal-clk {
compatible = "fixed-clock";
clock-frequency = <12000000>;
#clock-cells = <0>;
};
aliases {
watchdog0 = &wdt0;
};

View file

@ -11,3 +11,4 @@ CONFIG_BUILD_OUTPUT_UF2=y
CONFIG_BUILD_OUTPUT_HEX=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_RESET=y
CONFIG_CLOCK_CONTROL=y

View file

@ -11,3 +11,4 @@ CONFIG_BUILD_OUTPUT_UF2=y
CONFIG_BUILD_OUTPUT_HEX=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_RESET=y
CONFIG_CLOCK_CONTROL=y

View file

@ -23,12 +23,6 @@
aliases {
watchdog0 = &wdt0;
};
xtal_clk: xtal-clk {
compatible = "fixed-clock";
clock-frequency = <12000000>;
#clock-cells = <0>;
};
};
&flash0 {

View file

@ -15,6 +15,9 @@ CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
# Enable clock control by default
CONFIG_CLOCK_CONTROL=y
# Code partition needed to target the correct flash range
CONFIG_USE_DT_CODE_PARTITION=y

View file

@ -29,6 +29,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_cont
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RA clock_control_ra.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AMBIQ clock_control_ambiq.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_control_pwm.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_control_rpi_pico.c)
if(CONFIG_CLOCK_CONTROL_STM32_CUBE)

View file

@ -86,4 +86,6 @@ source "drivers/clock_control/Kconfig.ambiq"
source "drivers/clock_control/Kconfig.pwm"
source "drivers/clock_control/Kconfig.rpi_pico"
endif # CLOCK_CONTROL

View file

@ -0,0 +1,19 @@
# Raspberry Pi Pico Clock Controller Driver configuration options
# Copyright (c) 2022 Andrei-Edward Popa
# SPDX-License-Identifier: Apache-2.0
config CLOCK_CONTROL_RPI_PICO
bool "Raspberry Pi Pico Clock Controller Driver"
default y
depends on DT_HAS_RASPBERRYPI_PICO_CLOCK_CONTROLLER_ENABLED
if CLOCK_CONTROL_RPI_PICO
config RPI_PICO_ROSC_USE_MEASURED_FREQ
bool "Use measured frequency for ring oscillator"
help
Instead of the dts value, use the value measured by
the frequency counter as the rosc frequency.
endif # CLOCK_CONTROL_RPI_PICO

View file

@ -0,0 +1,876 @@
/*
* 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/reset.h>
#include <zephyr/dt-bindings/clock/rpi_pico_clock.h>
#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_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_rtc CLK_RTC
#define AUXSRC_clk_gpin0 CLKSRC_GPIN0
#define AUXSRC_clk_gpin1 CLKSRC_GPIN1
#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_rtc CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_
#define AUXSTEM_clk_peri CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_
#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,
rpi_pico_clkid_clk_rtc = RPI_PICO_CLKID_CLK_RTC,
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;
case rpi_pico_clkid_clk_rtc:
fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_RTC;
break;
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 = rpi_pico_clkid_none;
if (id == rpi_pico_clkid_clk_gpout0 || id == rpi_pico_clkid_clk_gpout1 ||
id == rpi_pico_clkid_clk_gpout2 || id == 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,
rpi_pico_clkid_clk_rtc,
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];
} else if (id == 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];
}
} else if (id == 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];
}
} else if (id == 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];
} else if (id == rpi_pico_clkid_clk_usb || id == rpi_pico_clkid_clk_adc ||
id == rpi_pico_clkid_clk_rtc) {
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];
} else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) {
srcid = rpi_pico_clkid_xosc;
}
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 ||
id == rpi_pico_clkid_clk_rtc ||
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 ||
id == rpi_pico_clkid_clk_rtc ||
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;
clocks_hw_t *clocks_regs = config->clocks_regs;
if (rpi_pico_is_valid_clock_index(clkid) < 0) {
return -EINVAL;
}
hw_set_bits(&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;
clocks_hw_t *clocks_regs = config->clocks_regs;
if (rpi_pico_is_valid_clock_index(clkid) < 0) {
return -EINVAL;
}
hw_clear_bits(&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_PLL_USB_BITS | RESETS_RESET_SYSCFG_BITS |
RESETS_RESET_PLL_SYS_BITS));
unreset_block_wait(RESETS_RESET_BITS &
~(RESETS_RESET_ADC_BITS | RESETS_RESET_RTC_BITS |
RESETS_RESET_SPI0_BITS | RESETS_RESET_SPI1_BITS |
RESETS_RESET_UART0_BITS | RESETS_RESET_UART1_BITS |
RESETS_RESET_USBCTRL_BITS | RESETS_RESET_PWM_BITS));
/* Start tick in watchdog */
watchdog_hw->tick = ((CLOCK_FREQ_xosc/1000000) | WATCHDOG_TICK_ENABLE_BITS);
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);
}
return 0;
}
static const struct clock_control_driver_api 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");
BUILD_ASSERT(SRC_CLOCK_FREQ(clk_rtc) >= CLOCK_FREQ_clk_rtc,
"clk_rtc: clock divider is out of range");
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");
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),
.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),
},
[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),
},
},
.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);

View file

@ -7,6 +7,7 @@
#include <arm/armv6-m.dtsi>
#include <zephyr/dt-bindings/adc/adc.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/clock/rpi_pico_clock.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/regulator/rpi_pico.h>
#include <mem.h>
@ -33,6 +34,149 @@
};
};
clocks {
clk_gpout0: clk-gpout0 {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_sys>;
clock-names = "pll_sys";
clock-frequency = <125000000>;
#clock-cells = <0>;
#address-cells = <0>;
};
clk_gpout1: clk-gpout1 {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_sys>;
clock-names = "pll_sys";
clock-frequency = <125000000>;
#clock-cells = <0>;
};
clk_gpout2: clk-gpout2 {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_sys>;
clock-names = "pll_sys";
clock-frequency = <125000000>;
#clock-cells = <0>;
};
clk_gpout3: clk-gpout3 {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_sys>;
clock-names = "pll_sys";
clock-frequency = <125000000>;
#clock-cells = <0>;
};
clk_ref: clk-ref {
compatible = "raspberrypi,pico-clock";
clocks = <&xosc>;
clock-names = "xosc";
clock-frequency = <12000000>;
#clock-cells = <0>;
};
clk_sys: clk-sys {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_sys>;
clock-names = "pll_sys";
clock-frequency = <125000000>;
#clock-cells = <0>;
};
clk_usb: clk-usb {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_usb>;
clock-names = "pll_usb";
clock-frequency = <48000000>;
#clock-cells = <0>;
};
clk_adc: clk-adc {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_usb>;
clock-names = "pll_usb";
clock-frequency = <48000000>;
#clock-cells = <0>;
};
clk_rtc: clk-rtc {
compatible = "raspberrypi,pico-clock";
clocks = <&pll_usb>;
clock-names = "pll_usb";
clock-frequency = <46875>;
#clock-cells = <0>;
};
clk_peri: clk-peri {
compatible = "raspberrypi,pico-clock";
clocks = <&clk_sys>;
clock-names = "clk_sys";
clock-frequency = <125000000>;
#clock-cells = <0>;
};
pll_sys: pll-sys {
compatible = "raspberrypi,pico-pll";
clocks = <&xosc>;
clock-names = "xosc";
clock-div= <1>;
fb-div= <125>;
post-div1 = <6>;
post-div2 = <2>;
#clock-cells = <0>;
};
pll_usb: pll-usb {
compatible = "raspberrypi,pico-pll";
clocks = <&xosc>;
clock-names = "xosc";
clock-div= <1>;
fb-div = <100>;
post-div1 = <5>;
post-div2 = <5>;
#clock-cells = <0>;
};
rosc: rosc {
compatible = "raspberrypi,pico-rosc";
clock-frequency = <6500000>;
range = <RPI_PICO_ROSC_RANGE_RESET>;
stage-drive-strength = <0>, <0>, <0>, <0>, <0>, <0>, <0>, <0>;
clock-div = <16>;
phase = <0>;
#clock-cells = <0>;
};
rosc_ph: rosc-ph {
compatible = "raspberrypi,pico-clock";
clock-frequency = <6500000>;
clocks = <&rosc>;
clock-names = "rosc";
#clock-cells = <0>;
};
xosc: xosc {
compatible = "raspberrypi,pico-clock";
clock-frequency = <12000000>;
#clock-cells = <0>;
};
gpin0: gpin0 {
compatible = "raspberrypi,pico-clock";
status = "disabled";
clock-frequency = <0>;
#clock-cells = <0>;
};
gpin1: gpin1 {
compatible = "raspberrypi,pico-clock";
status = "disabled";
clock-frequency = <0>;
#clock-cells = <0>;
};
};
soc {
compatible = "raspberrypi,rp2040", "simple-bus";
@ -55,18 +199,6 @@
};
};
peripheral_clk: peripheral-clk {
compatible = "fixed-clock";
clock-frequency = <125000000>;
#clock-cells = <0>;
};
system_clk: system-clk {
compatible = "fixed-clock";
clock-frequency = <125000000>;
#clock-cells = <0>;
};
reset: reset-controller@4000c000 {
compatible = "raspberrypi,pico-reset";
reg = <0x4000c000 DT_SIZE_K(4)>;
@ -75,6 +207,28 @@
#reset-cells = <1>;
};
clocks: clock-controller@40008000 {
compatible = "raspberrypi,pico-clock-controller";
reg = <0x40008000 DT_SIZE_K(4)
0x40024000 DT_SIZE_K(4)
0x40028000 DT_SIZE_K(4)
0x4002c000 DT_SIZE_K(4)
0x40060000 DT_SIZE_K(4)>;
reg-names = "clocks", "xosc", "pll_sys", "pll_usb", "rosc";
#clock-cells = <1>;
status = "okay";
clocks = <&clk_gpout0>, <&clk_gpout1>, <&clk_gpout2>, <&clk_gpout3>,
<&clk_ref>, <&clk_sys>, <&clk_peri>,
<&clk_usb>, <&clk_adc>, <&clk_rtc>,
<&pll_sys>, <&pll_usb>, <&xosc>, <&rosc>, <&rosc_ph>,
<&gpin0>, <&gpin1>;
clock-names = "clk_gpout0", "clk_gpout1", "clk_gpout2", "clk_gpout3",
"clk_ref", "clk_sys", "clk_peri",
"clk_usb", "clk_adc", "clk_rtc",
"pll_sys", "pll_usb", "xosc", "rosc", "rosc_ph",
"gpin0", "gpin1";
};
gpio0: gpio@40014000 {
compatible = "raspberrypi,pico-gpio";
reg = <0x40014000 DT_SIZE_K(4)>;
@ -88,7 +242,7 @@
uart0: uart@40034000 {
compatible = "raspberrypi,pico-uart";
reg = <0x40034000 DT_SIZE_K(4)>;
clocks = <&peripheral_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>;
resets = <&reset RPI_PICO_RESETS_RESET_UART0>;
interrupts = <20 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "uart0";
@ -98,7 +252,7 @@
uart1: uart@40038000 {
compatible = "raspberrypi,pico-uart";
reg = <0x40038000 DT_SIZE_K(4)>;
clocks = <&peripheral_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>;
resets = <&reset RPI_PICO_RESETS_RESET_UART1>;
interrupts = <21 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "uart1";
@ -110,7 +264,7 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x4003c000 DT_SIZE_K(4)>;
clocks = <&peripheral_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>;
resets = <&reset RPI_PICO_RESETS_RESET_SPI0>;
interrupts = <18 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "spi0";
@ -123,7 +277,7 @@
#size-cells = <0>;
reg = <0x40040000 DT_SIZE_K(4)>;
resets = <&reset RPI_PICO_RESETS_RESET_SPI1>;
clocks = <&peripheral_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>;
interrupts = <19 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "spi1";
status = "disabled";
@ -133,6 +287,7 @@
compatible = "raspberrypi,pico-adc";
reg = <0x4004c000 DT_SIZE_K(4)>;
resets = <&reset RPI_PICO_RESETS_RESET_ADC>;
clocks = <&clocks RPI_PICO_CLKID_CLK_ADC>;
interrupts = <22 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "adc0";
status = "disabled";
@ -145,7 +300,7 @@
#size-cells = <0>;
reg = <0x40044000 DT_SIZE_K(4)>;
resets = <&reset RPI_PICO_RESETS_RESET_I2C0>;
clocks = <&system_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>;
interrupts = <23 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "i2c0";
status = "disabled";
@ -157,7 +312,7 @@
#size-cells = <0>;
reg = <0x40048000 DT_SIZE_K(4)>;
resets = <&reset RPI_PICO_RESETS_RESET_I2C0>;
clocks = <&system_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>;
interrupts = <24 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "i2c1";
status = "disabled";
@ -166,7 +321,7 @@
wdt0: watchdog@40058000 {
compatible = "raspberrypi,pico-watchdog";
reg = <0x40058000 DT_SIZE_K(4)>;
clocks = <&xtal_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_REF>;
status = "disabled";
};
@ -174,6 +329,7 @@
compatible = "raspberrypi,pico-usbd";
reg = <0x50100000 0x10000>;
resets = <&reset RPI_PICO_RESETS_RESET_USBCTRL>;
clocks = <&clocks RPI_PICO_CLKID_CLK_USB>;
interrupts = <5 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "usbctrl";
num-bidir-endpoints = <16>;
@ -184,7 +340,7 @@
compatible = "raspberrypi,pico-pwm";
reg = <0x40050000 DT_SIZE_K(4)>;
resets = <&reset RPI_PICO_RESETS_RESET_PWM>;
clocks = <&system_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>;
interrupts = <4 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "PWM_IRQ_WRAP";
status = "disabled";
@ -195,7 +351,7 @@
compatible = "raspberrypi,pico-timer";
reg = <0x40054000 DT_SIZE_K(4)>;
resets = <&reset RPI_PICO_RESETS_RESET_TIMER>;
clocks = <&xtal_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_REF>;
interrupts = <0 RPI_PICO_DEFAULT_IRQ_PRIORITY>,
<1 RPI_PICO_DEFAULT_IRQ_PRIORITY>,
<2 RPI_PICO_DEFAULT_IRQ_PRIORITY>,
@ -211,7 +367,7 @@
compatible = "raspberrypi,pico-dma";
reg = <0x50000000 DT_SIZE_K(64)>;
resets = <&reset RPI_PICO_RESETS_RESET_DMA>;
clocks = <&system_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>;
interrupts = <11 RPI_PICO_DEFAULT_IRQ_PRIORITY>,
<12 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "dma0", "dma1";
@ -231,7 +387,7 @@
pio0: pio@50200000 {
compatible = "raspberrypi,pico-pio";
reg = <0x50200000 DT_SIZE_K(4)>;
clocks = <&system_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>;
resets = <&reset RPI_PICO_RESETS_RESET_PIO0>;
status = "disabled";
};
@ -239,7 +395,7 @@
pio1: pio@50300000 {
compatible = "raspberrypi,pico-pio";
reg = <0x50300000 DT_SIZE_K(4)>;
clocks = <&system_clk>;
clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>;
resets = <&reset RPI_PICO_RESETS_RESET_PIO1>;
status = "disabled";
};

View file

@ -0,0 +1,18 @@
# Copyright (c) 2022 Andrei-Edward Popa
# SPDX-License-Identifier: Apache-2.0
description: Raspberry Pi Pico clock controller node
compatible: "raspberrypi,pico-clock-controller"
include: [base.yaml, clock-controller.yaml]
properties:
reg:
required: true
"#clock-cells":
const: 1
clock-cells:
- clk-id

View file

@ -0,0 +1,18 @@
# Copyright (c) 2023 TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0
description: |
The representation of Raspberry Pi Pico's clock
compatible: "raspberrypi,pico-clock"
include: fixed-clock.yaml
properties:
clocks:
type: phandle-array
description: Clock gate information
clock-names:
type: string-array
description: name of each clock

View file

@ -0,0 +1,31 @@
# Copyright (c) 2023 TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0
description: |
The representation of Raspberry Pi Pico's PLL.
compatible: "raspberrypi,pico-pll"
include: [base.yaml, fixed-factor-clock.yaml]
properties:
fb-div:
type: int
required: true
description: |
The feedback divider value.
The valid range is 16 to 320.
post-div1:
type: int
required: true
description: |
The post clock divider.
The valid range is 1 to 49.
post-div2:
type: int
required: true
description: |
The post clock divider.
The valid range is 1 to 49.

View file

@ -0,0 +1,38 @@
# Copyright (c) 2023 TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0
description: |
The representation of Raspberry Pi Pico ring oscillator.
compatible: "raspberrypi,pico-rosc"
include: [fixed-clock.yaml, fixed-factor-clock.yaml]
properties:
range:
type: int
required: true
description: |
Specify the number of ring oscillator stages to use.
- LOW: 8 (default)
- MEDIUM: 6
- HIGH: 4
- TOOHIGH: 2
stage-drive-strength:
type: array
required: true
description: |
Specifies the drive strength of the eight stages of the ring oscillator.
The valid range of each value is between 0 and 7.
phase-flip:
type: boolean
description: |
Flipping phase-shifter output.
phase:
type: int
description: |
The phase-shift vlaue.
The valid range is 0 to 3

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2022 Andrei-Edward Popa
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_
#define RPI_PICO_PLL_SYS 0
#define RPI_PICO_PLL_USB 1
#define RPI_PICO_PLL_COUNT 2
#define RPI_PICO_GPIN_0 0
#define RPI_PICO_GPIN_1 1
#define RPI_PICO_GPIN_COUNT 2
#define RPI_PICO_CLKID_CLK_GPOUT0 0
#define RPI_PICO_CLKID_CLK_GPOUT1 1
#define RPI_PICO_CLKID_CLK_GPOUT2 2
#define RPI_PICO_CLKID_CLK_GPOUT3 3
#define RPI_PICO_CLKID_CLK_REF 4
#define RPI_PICO_CLKID_CLK_SYS 5
#define RPI_PICO_CLKID_CLK_PERI 6
#define RPI_PICO_CLKID_CLK_USB 7
#define RPI_PICO_CLKID_CLK_ADC 8
#define RPI_PICO_CLKID_CLK_RTC 9
#define RPI_PICO_CLKID_PLL_SYS 10
#define RPI_PICO_CLKID_PLL_USB 11
#define RPI_PICO_CLKID_XOSC 12
#define RPI_PICO_CLKID_ROSC 13
#define RPI_PICO_CLKID_ROSC_PH 14
#define RPI_PICO_CLKID_GPIN0 15
#define RPI_PICO_CLKID_GPIN1 16
#define RPI_PICO_ROSC_RANGE_RESET 0xAA0
#define RPI_PICO_ROSC_RANGE_LOW 0xFA4
#define RPI_PICO_ROSC_RANGE_MEDIUM 0xFA5
#define RPI_PICO_ROSC_RANGE_HIGH 0xFA7
#define RPI_PICO_ROSC_RANGE_TOOHIGH 0xFA6
#define RPI_PICO_CLOCK_COUNT 10
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_ */

View file

@ -219,4 +219,11 @@
#define PIO1_P28 RP2040_PINMUX(28, RP2_PINCTRL_GPIO_FUNC_PIO1)
#define PIO1_P29 RP2040_PINMUX(29, RP2_PINCTRL_GPIO_FUNC_PIO1)
#define GPIN0_P20 RP2040_PINMUX(20, RP2_PINCTRL_GPIO_FUNC_GPCK)
#define GPIN1_P22 RP2040_PINMUX(22, RP2_PINCTRL_GPIO_FUNC_GPCK)
#define GPOUT0_P21 RP2040_PINMUX(21, RP2_PINCTRL_GPIO_FUNC_GPCK)
#define GPOUT1_P23 RP2040_PINMUX(23, RP2_PINCTRL_GPIO_FUNC_GPCK)
#define GPOUT2_P24 RP2040_PINMUX(24, RP2_PINCTRL_GPIO_FUNC_GPCK)
#define GPOUT3_P25 RP2040_PINMUX(25, RP2_PINCTRL_GPIO_FUNC_GPCK)
#endif /* __RP2040_PINCTRL_H__ */

View file

@ -22,7 +22,7 @@
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
clocks = < &system_clk >;
clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>;
miso-gpios = <&gpio0 12 0>;
cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
clk-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;

View file

@ -26,24 +26,6 @@
LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
static int rp2040_init(void)
{
reset_block(~(RESETS_RESET_IO_QSPI_BITS | RESETS_RESET_PADS_QSPI_BITS |
RESETS_RESET_PLL_USB_BITS | RESETS_RESET_PLL_SYS_BITS));
unreset_block_wait(RESETS_RESET_BITS &
~(RESETS_RESET_ADC_BITS | RESETS_RESET_RTC_BITS |
RESETS_RESET_SPI0_BITS | RESETS_RESET_SPI1_BITS |
RESETS_RESET_UART0_BITS | RESETS_RESET_UART1_BITS |
RESETS_RESET_USBCTRL_BITS | RESETS_RESET_PWM_BITS));
clocks_init();
unreset_block_wait(RESETS_RESET_BITS);
return 0;
}
/*
* Some pico-sdk drivers call panic on fatal error.
* This alternative implementation of panic handles the panic
@ -57,5 +39,3 @@ void __attribute__((noreturn)) panic(const char *fmt, ...)
vprintf(fmt, args);
k_fatal_halt(K_ERR_CPU_EXCEPTION);
}
SYS_INIT(rp2040_init, PRE_KERNEL_1, 0);