| /* |
| * 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> |
| #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); |
| } |
| |
| ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); |
| if (ret < 0) { |
| return ret; |
| } |
| |
| 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"); |
| |
| 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), |
| }, |
| [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); |