diff --git a/boards/microchip/pic32c/pic32cm_jh01_cpro/pic32cm_jh01_cpro.dts b/boards/microchip/pic32c/pic32cm_jh01_cpro/pic32cm_jh01_cpro.dts index be9040dacadb9..ce7264ae3d073 100644 --- a/boards/microchip/pic32c/pic32cm_jh01_cpro/pic32cm_jh01_cpro.dts +++ b/boards/microchip/pic32c/pic32cm_jh01_cpro/pic32cm_jh01_cpro.dts @@ -56,5 +56,71 @@ }; &cpu0 { - clock-frequency = <4000000>; + clock-frequency = <48000000>; +}; + +&clock { + compatible = "microchip,pic32cm-jh-clock"; + + /* If cpu sourced from osc48m, use 3 for CPU frequency above 24Mhz */ + flash-wait-states = <2>; + + xosc: xosc { + compatible = "microchip,pic32cm-jh-xosc"; + xosc-frequency = <32000000>; + xosc-en = <1>; + xosc-xtal-en = <1>; + xosc-run-in-standby-en = <1>; + }; + + fdpll: fdpll { + compatible = "microchip,pic32cm-jh-fdpll"; + fdpll-xosc-clock-divider = <15>; + fdpll-divider-ratio-frac = <0>; + fdpll-divider-ratio-int = <95>; + fdpll-output-prescalar = "div2"; + fdpll-src = "xosc"; + fdpll-run-in-standby-en = <1>; + fdpll-en = <1>; + }; + + xosc32k: xosc32k { + compatible = "microchip,pic32cm-jh-xosc32k"; + xosc32k-32khz-en = <1>; + xosc32k-xtal-en = <1>; + xosc32k-startup-time = "122-us"; + xosc32k-run-in-standby-en = <1>; + xosc32k-en = <1>; + }; + + osc32k: osc32k { + compatible = "microchip,pic32cm-jh-osc32k"; + osc32k-32khz-en = <1>; + osc32k-startup-time = "183-us"; + osc32k-run-in-standby-en = <1>; + osc32k-en = <0>; + }; + + gclkgen: gclkgen { + compatible = "microchip,pic32cm-jh-gclkgen"; + + gclkgen0 { + subsystem = ; + gclkgen-div-factor = <1>; + gclkgen-run-in-standby-en = <1>; + gclkgen-src = "fdpll"; + gclkgen-en = <1>; + }; + }; + + gclkperiph: gclkperiph { + compatible = "microchip,pic32cm-jh-gclkperiph"; + #clock-cells = <1>; + + sercom2 { + subsystem = ; + gclkperiph-src = "gclk0"; + gclkperiph-en = <1>; + }; + }; }; diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 248e4d8f822af..3b68a07708b5f 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_GD32 clock_control_gd32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LITEX clock_control_litex.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LPC11U6X clock_control_lpc11u6x.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_PIC32CM_JH clock_control_mchp_pic32cm_jh.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_SAM_D5X_E5X clock_control_mchp_sam_d5x_e5x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_XEC clock_control_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM clock_control_mcux_ccm.c) diff --git a/drivers/clock_control/Kconfig.mchp b/drivers/clock_control/Kconfig.mchp index 60a9bf5467a36..2c9339c859f86 100644 --- a/drivers/clock_control/Kconfig.mchp +++ b/drivers/clock_control/Kconfig.mchp @@ -2,20 +2,46 @@ # SPDX-License-Identifier: Apache-2.0 config CLOCK_CONTROL_MCHP_COMMON - bool + bool "Microchip clock controller" help Common options for Microchip clock control drivers. config CLOCK_CONTROL_MCHP_SAM_D5X_E5X - bool "Microchip SAM D5X/E5X clock controller Support" + bool depends on DT_HAS_MICROCHIP_SAM_D5X_E5X_CLOCK_ENABLED default y select CLOCK_CONTROL_MCHP_COMMON help Enable clock controller driver for Microchip SAM D5X/E5X SoC family. +config CLOCK_CONTROL_MCHP_PIC32CM_JH + bool + default y + depends on DT_HAS_MICROCHIP_PIC32CM_JH_CLOCK_ENABLED + select CLOCK_CONTROL_MCHP_COMMON + help + Enable clock controller driver for Microchip PIC32CM_JH family. + if CLOCK_CONTROL_MCHP_COMMON +config CLOCK_CONTROL_MCHP_CONFIG_BOOTUP + bool "Bootup clock configuration" + default y + help + This option enables bootup clock configuration from device tree node. + +config CLOCK_CONTROL_MCHP_CONFIG_RUNTIME + bool "Runtime clock configuration" + default y + help + This option enables runtime clock configuration using API. + +config CLOCK_CONTROL_MCHP_ASYNC_ON + bool "Async clock on" + default n + help + This option enables async on API. + config CLOCK_CONTROL_MCHP_GET_RATE bool "Get clock rate" default y @@ -23,4 +49,12 @@ config CLOCK_CONTROL_MCHP_GET_RATE Enable support for retrieving the clock rate. This may increase code size, depending on the depth of clock source hierarchy. +config CLOCK_CONTROL_MCHP_SET_RATE + bool "Set clock rate" + default n + depends on CLOCK_CONTROL_MCHP_GET_RATE + help + This option enables set rate API. This may increase + code size, depending on the depth of clock source hierarchy. + endif # CLOCK_CONTROL_MCHP_COMMON diff --git a/drivers/clock_control/clock_control_mchp_pic32cm_jh.c b/drivers/clock_control/clock_control_mchp_pic32cm_jh.c new file mode 100644 index 0000000000000..da4dc813a9e9f --- /dev/null +++ b/drivers/clock_control/clock_control_mchp_pic32cm_jh.c @@ -0,0 +1,1981 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file clock_control_mchp_pic32cm_jh.c + * @brief Clock control driver for pic32cm_jh family devices. + */ + +#include +#include +#include +#include + +#include + +/****************************************************************************** + * @brief Devicetree definitions + *****************************************************************************/ +#define DT_DRV_COMPAT microchip_pic32cm_jh_clock + +/****************************************************************************** + * @brief Macro definitions + *****************************************************************************/ +LOG_MODULE_REGISTER(clock_mchp_pic32cm_jh, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define CLOCK_NODE DT_NODELABEL(clock) + +#define CLOCK_SUCCESS 0 + +/* Properties not exposed in binding file, initialize to values given below */ +#define CLOCK_OSCCTRL_XOSCCTRL_GAIN_VALUE (4) + +/* Frequency values */ +#define FREQ_32KHZ 32768 +#define FREQ_1KHZ 1024 +#define FREQ_48MHZ 48000000 +#define FREQ_96MHZ 96000000 + +/* maximum value for gclk pin I/O channel, 0 - 7 */ +#define GCLK_IO_MAX 7 + +/* gclk peripheral channel max, 0 - 47 */ +#define GPH_MAX 47 + +/* maximum value for mask bit position, 0 - 31 */ +#define MMASK_MAX 31 + +/* maximum value for div, when div_select is clock source frequency divided by 2^(N+1) */ +#define GCLKGEN_POWER_DIV_MAX 29 + +/* init iteration count, so that, the source clocks are initialized before executing init */ +#define CLOCK_INIT_ITERATION_COUNT 3 + +/* mclkbus Not Applicable for a clock subsystem ID */ +#define MBUS_NA (0x3f) + +/* mclkmaskbit Not Applicable for a clock subsystem ID */ +#define MMASK_NA (0x3f) + +/* gclkperiph Not Applicable for a clock subsystem ID */ +#define GPH_NA (0x3f) + +/* Clock subsystem Types */ +#define SUBSYS_TYPE_XOSC (0) +#define SUBSYS_TYPE_OSC48M (1) +#define SUBSYS_TYPE_FDPLL (2) +#define SUBSYS_TYPE_RTC (3) +#define SUBSYS_TYPE_XOSC32K (4) +#define SUBSYS_TYPE_OSC32K (5) +#define SUBSYS_TYPE_GCLKGEN (6) +#define SUBSYS_TYPE_GCLKPERIPH (7) +#define SUBSYS_TYPE_MCLKCPU (8) +#define SUBSYS_TYPE_MCLKPERIPH (9) +#define SUBSYS_TYPE_MAX (9) + +/* mclk bus */ +#define MBUS_AHB (0) +#define MBUS_APBA (1) +#define MBUS_APBB (2) +#define MBUS_APBC (3) +#define MBUS_APBD (4) +#define MBUS_MAX (4) + +/* XOSC32K instances */ +#define INST_XOSC32K_XOSC1K 0 +#define INST_XOSC32K_XOSC32K 1 + +/* OSC32K instances */ +#define INST_OSC32K_OSC1K 0 +#define INST_OSC32K_OSC32K 1 + +/****************************************************************************** + * @brief Data type definitions + *****************************************************************************/ +/** @brief Clock subsystem definition. + * + * Structure which can be used as a sys argument in the clock_control API. + * Encode clock type, mclk bus, mclk mask bit, gclk pch and instance number, + * to clock subsystem. + * + * - 00..07 (8 bits): inst + * - 08..13 (6 bits): gclkperiph + * - 14..19 (6 bits): mclkmaskbit + * - 20..25 (6 bits): mclkbus + * - 26..31 (6 bits): type + */ +typedef union { + uint32_t val; + struct { + uint32_t inst: 8; + uint32_t gclkperiph: 6; + uint32_t mclkmaskbit: 6; + uint32_t mclkbus: 6; + uint32_t type: 6; + } bits; +} clock_mchp_subsys_t; + +#if CONFIG_CLOCK_CONTROL_MCHP_CONFIG_BOOTUP +/** @brief XOSC initialization structure. */ +typedef struct { + uint8_t startup_time; /* XOSCCTRL */ + uint8_t automatic_amplitude_gain_control_en; /* XOSCCTRL */ + uint8_t on_demand_en; /* XOSCCTRL */ + uint8_t run_in_standby_en; /* XOSCCTRL */ + uint8_t clock_failure_detection_en; /* XOSCCTRL */ + uint8_t xtal_en; /* XOSCCTRL */ + uint8_t enable; /* XOSCCTRL */ + + uint32_t frequency; +} clock_xosc_init_t; + +/** @brief OSC48M initialization structure. */ +typedef struct { + uint8_t on_demand_en; /* OSC48MCTRL */ + uint8_t run_in_standby_en; /* OSC48MCTRL */ + uint8_t enable; /* OSC48MCTRL */ + + uint8_t post_divider_freq; /* OSC48MDIV */ +} clock_osc48m_init_t; + +/** @brief FDPLL initialization structure. */ +typedef struct { + uint8_t on_demand_en; /* DPLLCTRLA */ + uint8_t run_in_standby_en; /* DPLLCTRLA */ + uint8_t enable; /* DPLLCTRLA */ + + uint8_t divider_ratio_frac; /* DPLLRATIO */ + uint16_t divider_ratio_int; /* DPLLRATIO */ + + uint16_t xosc_clock_divider; /* DPLLCTRLB */ + uint8_t lock_bypass_en; /* DPLLCTRLB */ + uint8_t src; /* DPLLCTRLB */ + uint8_t wakeup_fast_en; /* DPLLCTRLB */ + uint8_t low_power_en; /* DPLLCTRLB */ + uint8_t pi_filter_type; /* DPLLCTRLB */ + + uint8_t output_prescalar; /* DPLLPRESC */ +} clock_fdpll_init_t; + +/** @brief XOSC32K initialization structure. */ +typedef struct { + uint8_t startup_time; /* XOSC32K */ + uint8_t on_demand_en; /* XOSC32K */ + uint8_t run_in_standby_en; /* XOSC32K */ + uint8_t xosc32k_1khz_en; /* XOSC32K */ + uint8_t xosc32k_32khz_en; /* XOSC32K */ + uint8_t xtal_en; /* XOSC32K */ + uint8_t enable; /* XOSC32K */ + + uint8_t cfd_en; /* CFDCTRL */ +} clock_xosc32k_init_t; + +/** @brief OSC32K initialization structure. */ +typedef struct { + uint8_t startup_time; /* OSC32K */ + uint8_t on_demand_en; /* OSC32K */ + uint8_t run_in_standby_en; /* OSC32K */ + uint8_t osc32k_1khz_en; /* OSC32K */ + uint8_t osc32k_32khz_en; /* OSC32K */ + uint8_t enable; /* OSC32K */ +} clock_osc32k_init_t; + +/** @brief GCLKGEN initialization structure. */ +typedef struct { + clock_mchp_subsys_t subsys; + uint16_t div_factor; /* GENCTRLx */ + uint8_t run_in_standby_en; /* GENCTRLx */ + uint8_t div_select; /* GENCTRLx */ + uint8_t pin_output_en; /* GENCTRLx */ + uint8_t pin_output_off_val; /* GENCTRLx */ + uint8_t improve_duty_cycle_en; /* GENCTRLx */ + uint8_t enable; /* GENCTRLx */ + uint8_t src; /* GENCTRLx */ + + uint32_t pin_src_freq; +} clock_gclkgen_init_t; +#endif /* CONFIG_CLOCK_CONTROL_MCHP_CONFIG_BOOTUP */ + +/** @brief clock driver configuration structure. */ +typedef struct { + oscctrl_registers_t *oscctrl_regs; + osc32kctrl_registers_t *osc32kctrl_regs; + gclk_registers_t *gclk_regs; + mclk_registers_t *mclk_regs; + + /* Timeout in milliseconds to wait for clock to turn on */ + uint32_t on_timeout_ms; + + /* Number of wait states for a flash read operation */ + uint8_t flash_wait_states; +} clock_mchp_config_t; + +/** @brief clock driver data structure. */ +typedef struct { + + uint32_t xosc_crystal_freq; + uint32_t gclkpin_freq[GCLK_IO_MAX + 1]; + + /* + * Use bit position as per enum clock_mchp_fdpll_src_clock_t, to show if the specified + * clock source to FDPLL is on. + */ + uint16_t fdpll_src_on_status; + + /* + * Use bit position as per enum clock_mchp_gclk_src_clock_t, to show if the specified + * clock source to gclk generator is on. + */ + uint16_t gclkgen_src_on_status; + + clock_mchp_gclk_src_clock_t gclk0_src; +} clock_mchp_data_t; + +/****************************************************************************** + * @brief Function forward declarations + *****************************************************************************/ +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE +static int clock_get_rate_osc48m(const struct device *dev, uint32_t *freq); +static int clock_get_rate_fdpll(const struct device *dev, uint32_t *freq); +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ + +static enum clock_control_status clock_mchp_get_status(const struct device *dev, + clock_control_subsys_t sys); + +/****************************************************************************** + * @brief Helper functions + *****************************************************************************/ +/** + * @brief check if subsystem type and id are valid. + */ +static int clock_check_subsys(clock_mchp_subsys_t subsys) +{ + int ret_val = -EINVAL; + uint32_t inst_max = 0, gclkperiph_max = GPH_NA, mclkbus_max = MBUS_NA, + mclkmaskbit_max = MMASK_NA; + + do { + /* Check if turning on all clocks is requested. */ + if (subsys.val == (uint32_t)CLOCK_CONTROL_SUBSYS_ALL) { + break; + } + + /* Check if the specified subsystem was found. */ + if (subsys.bits.type > SUBSYS_TYPE_MAX) { + break; + } + + switch (subsys.bits.type) { + case SUBSYS_TYPE_XOSC: + inst_max = CLOCK_MCHP_XOSC_ID_MAX; + break; + + case SUBSYS_TYPE_OSC48M: + inst_max = CLOCK_MCHP_OSC48M_ID_MAX; + break; + + case SUBSYS_TYPE_FDPLL: + inst_max = CLOCK_MCHP_FDPLL_ID_MAX; + gclkperiph_max = CLOCK_MCHP_FDPLL_ID_MAX; + break; + + case SUBSYS_TYPE_RTC: + inst_max = CLOCK_MCHP_RTC_ID_MAX; + break; + + case SUBSYS_TYPE_XOSC32K: + inst_max = CLOCK_MCHP_XOSC32K_ID_MAX; + break; + + case SUBSYS_TYPE_OSC32K: + inst_max = CLOCK_MCHP_OSC32K_ID_MAX; + break; + + case SUBSYS_TYPE_GCLKGEN: + inst_max = CLOCK_MCHP_GCLKGEN_ID_MAX; + break; + + case SUBSYS_TYPE_GCLKPERIPH: + inst_max = CLOCK_MCHP_GCLKPERIPH_ID_MAX; + gclkperiph_max = GPH_MAX; + break; + + case SUBSYS_TYPE_MCLKCPU: + inst_max = CLOCK_MCHP_MCLKCPU_MAX; + break; + + case SUBSYS_TYPE_MCLKPERIPH: + inst_max = CLOCK_MCHP_MCLKPERIPH_ID_MAX; + mclkbus_max = MBUS_MAX; + mclkmaskbit_max = MMASK_MAX; + break; + + default: + LOG_ERR("Unsupported SUBSYS_TYPE"); + } + + /* Check if the specified id is valid. */ + if ((subsys.bits.inst > inst_max) || (subsys.bits.gclkperiph > gclkperiph_max) || + (subsys.bits.mclkbus > mclkbus_max) || + (subsys.bits.mclkmaskbit > mclkmaskbit_max)) { + break; + } + + ret_val = CLOCK_SUCCESS; + } while (0); + + return ret_val; +} + +/** + * @brief get the address of mclk mask register. + */ +__IO uint32_t *get_mclkbus_mask_reg(mclk_registers_t *mclk_regs, uint32_t bus) +{ + __IO uint32_t *reg32 = NULL; + + switch (bus) { + case MBUS_AHB: + reg32 = &mclk_regs->MCLK_AHBMASK; + break; + case MBUS_APBA: + reg32 = &mclk_regs->MCLK_APBAMASK; + break; + case MBUS_APBB: + reg32 = &mclk_regs->MCLK_APBBMASK; + break; + case MBUS_APBC: + reg32 = &mclk_regs->MCLK_APBCMASK; + break; + case MBUS_APBD: + reg32 = &mclk_regs->MCLK_APBDMASK; + break; + default: + LOG_ERR("Unsupported mclkbus"); + break; + } + + return reg32; +} + +/** + * @brief get status of respective clock subsystem. + */ +static enum clock_control_status clock_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + enum clock_control_status ret_status = CLOCK_CONTROL_STATUS_UNKNOWN; + const clock_mchp_config_t *config = dev->config; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + gclk_registers_t *gclk_regs = config->gclk_regs; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + uint8_t inst = subsys.bits.inst; + uint32_t mask; + + __IO uint32_t *reg32 = NULL; + + switch (subsys.bits.type) { + case SUBSYS_TYPE_XOSC: + /* Check if XOSC is enabled */ + if ((oscctrl_regs->OSCCTRL_XOSCCTRL & OSCCTRL_XOSCCTRL_ENABLE_Msk) != 0) { + /* Check if ready bit is set */ + ret_status = + ((oscctrl_regs->OSCCTRL_STATUS & OSCCTRL_STATUS_XOSCRDY_Msk) == 0) + ? CLOCK_CONTROL_STATUS_STARTING + : CLOCK_CONTROL_STATUS_ON; + } else { + ret_status = CLOCK_CONTROL_STATUS_OFF; + } + + break; + case SUBSYS_TYPE_OSC48M: + /* Check if OSC48M is enabled */ + if ((oscctrl_regs->OSCCTRL_OSC48MCTRL & OSCCTRL_OSC48MCTRL_ENABLE_Msk) != 0) { + /* Check if ready bit is set */ + ret_status = + ((oscctrl_regs->OSCCTRL_STATUS & OSCCTRL_STATUS_OSC48MRDY_Msk) == 0) + ? CLOCK_CONTROL_STATUS_STARTING + : CLOCK_CONTROL_STATUS_ON; + } else { + ret_status = CLOCK_CONTROL_STATUS_OFF; + } + + break; + case SUBSYS_TYPE_FDPLL: + /* Check if DPLL is enabled */ + if ((oscctrl_regs->OSCCTRL_DPLLCTRLA & OSCCTRL_DPLLCTRLA_ENABLE_Msk) != 0) { + mask = OSCCTRL_DPLLSTATUS_LOCK_Msk | OSCCTRL_DPLLSTATUS_CLKRDY_Msk; + + /* Check if sync is complete and ready bit is set */ + ret_status = ((oscctrl_regs->OSCCTRL_DPLLSYNCBUSY != 0) || + ((oscctrl_regs->OSCCTRL_DPLLSTATUS & mask) != mask)) + ? CLOCK_CONTROL_STATUS_STARTING + : CLOCK_CONTROL_STATUS_ON; + } else { + ret_status = CLOCK_CONTROL_STATUS_OFF; + } + break; + case SUBSYS_TYPE_RTC: + ret_status = CLOCK_CONTROL_STATUS_ON; + break; + case SUBSYS_TYPE_XOSC32K: + /* For XOSC32K get_status return status of only EN1K or EN32K bits, + * which does not indicate the rdy status. + */ + if (inst == INST_XOSC32K_XOSC1K) { + mask = OSC32KCTRL_XOSC32K_ENABLE_Msk | OSC32KCTRL_XOSC32K_EN1K_Msk; + ret_status = ((osc32kctrl_regs->OSC32KCTRL_XOSC32K & mask) == mask) + ? CLOCK_CONTROL_STATUS_ON + : CLOCK_CONTROL_STATUS_OFF; + } else { + mask = OSC32KCTRL_XOSC32K_ENABLE_Msk | OSC32KCTRL_XOSC32K_EN32K_Msk; + ret_status = ((osc32kctrl_regs->OSC32KCTRL_XOSC32K & mask) == mask) + ? CLOCK_CONTROL_STATUS_ON + : CLOCK_CONTROL_STATUS_OFF; + } + break; + case SUBSYS_TYPE_OSC32K: + /* For OSC32K get_status return status of only EN1K or EN32K bits, + * which does not indicate the rdy status. + */ + if (inst == INST_OSC32K_OSC1K) { + mask = OSC32KCTRL_OSC32K_ENABLE_Msk | OSC32KCTRL_OSC32K_EN1K_Msk; + ret_status = ((osc32kctrl_regs->OSC32KCTRL_OSC32K & mask) == mask) + ? CLOCK_CONTROL_STATUS_ON + : CLOCK_CONTROL_STATUS_OFF; + } else { + mask = OSC32KCTRL_OSC32K_ENABLE_Msk | OSC32KCTRL_OSC32K_EN32K_Msk; + ret_status = ((osc32kctrl_regs->OSC32KCTRL_OSC32K & mask) == mask) + ? CLOCK_CONTROL_STATUS_ON + : CLOCK_CONTROL_STATUS_OFF; + } + break; + case SUBSYS_TYPE_GCLKGEN: + ret_status = CLOCK_CONTROL_STATUS_OFF; + if ((gclk_regs->GCLK_GENCTRL[inst] & GCLK_GENCTRL_GENEN_Msk) != 0) { + /* Generator is on, check if it's starting or fully on */ + ret_status = ((gclk_regs->GCLK_SYNCBUSY & + (1 << (GCLK_SYNCBUSY_GENCTRL_Pos + inst))) != 0) + ? CLOCK_CONTROL_STATUS_STARTING + : CLOCK_CONTROL_STATUS_ON; + } + break; + case SUBSYS_TYPE_GCLKPERIPH: + /* Check if the peripheral clock is enabled */ + ret_status = ((gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] & + GCLK_PCHCTRL_CHEN_Msk) != 0) + ? CLOCK_CONTROL_STATUS_ON + : CLOCK_CONTROL_STATUS_OFF; + break; + case SUBSYS_TYPE_MCLKCPU: + ret_status = CLOCK_CONTROL_STATUS_ON; + break; + case SUBSYS_TYPE_MCLKPERIPH: + reg32 = get_mclkbus_mask_reg(config->mclk_regs, subsys.bits.mclkbus); + mask = 1 << subsys.bits.mclkmaskbit; + ret_status = + ((*reg32 & mask) != 0) ? CLOCK_CONTROL_STATUS_ON : CLOCK_CONTROL_STATUS_OFF; + break; + default: + break; + } + + /* Return the status of the clock for the specified subsystem. */ + return ret_status; +} + +/** + * @brief function to set/clear clock subsystem enable bit. + */ +static int clock_on(const clock_mchp_config_t *config, const clock_mchp_subsys_t subsys) +{ + int ret_val = CLOCK_SUCCESS; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + gclk_registers_t *gclk_regs = config->gclk_regs; + uint8_t inst = subsys.bits.inst; + + __IO uint32_t *reg32 = NULL; + + switch (subsys.bits.type) { + case SUBSYS_TYPE_XOSC: + oscctrl_regs->OSCCTRL_XOSCCTRL |= OSCCTRL_XOSCCTRL_ENABLE_Msk; + break; + case SUBSYS_TYPE_OSC48M: + oscctrl_regs->OSCCTRL_OSC48MCTRL |= OSCCTRL_OSC48MCTRL_ENABLE_Msk; + break; + case SUBSYS_TYPE_FDPLL: + oscctrl_regs->OSCCTRL_DPLLCTRLA |= OSCCTRL_DPLLCTRLA_ENABLE_Msk; + break; + case SUBSYS_TYPE_XOSC32K: + if (inst == INST_XOSC32K_XOSC1K) { + osc32kctrl_regs->OSC32KCTRL_XOSC32K |= OSC32KCTRL_XOSC32K_EN1K_Msk; + } else { + osc32kctrl_regs->OSC32KCTRL_XOSC32K |= OSC32KCTRL_XOSC32K_EN32K_Msk; + } + + /* turn on XOSC32K if any of EN1K or EN32K is to be on */ + osc32kctrl_regs->OSC32KCTRL_XOSC32K |= OSC32KCTRL_XOSC32K_ENABLE_Msk; + + break; + case SUBSYS_TYPE_OSC32K: + if (inst == INST_OSC32K_OSC1K) { + osc32kctrl_regs->OSC32KCTRL_OSC32K |= OSC32KCTRL_OSC32K_EN1K_Msk; + } else { + osc32kctrl_regs->OSC32KCTRL_OSC32K |= OSC32KCTRL_OSC32K_EN32K_Msk; + } + + /* turn on OSC32K if any of EN1K or EN32K is to be on */ + osc32kctrl_regs->OSC32KCTRL_OSC32K |= OSC32KCTRL_OSC32K_ENABLE_Msk; + break; + case SUBSYS_TYPE_GCLKGEN: + /* Check if the clock is GCLKGEN0, which is always on */ + if (inst == CLOCK_MCHP_GCLKGEN_GEN0) { + /* GCLK GEN0 is always on */ + break; + } + + /* Enable the clock generator by setting the GENEN bit */ + gclk_regs->GCLK_GENCTRL[inst] |= GCLK_GENCTRL_GENEN_Msk; + break; + case SUBSYS_TYPE_GCLKPERIPH: + gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] |= GCLK_PCHCTRL_CHEN_Msk; + break; + case SUBSYS_TYPE_MCLKPERIPH: + reg32 = get_mclkbus_mask_reg(config->mclk_regs, subsys.bits.mclkbus); + *reg32 |= 1 << subsys.bits.mclkmaskbit; + break; + default: + ret_val = -ENOTSUP; + break; + } + + return ret_val; +} + +/** + * @brief function to set/clear clock subsystem enable bit. + */ +static int clock_off(const clock_mchp_config_t *config, const clock_mchp_subsys_t subsys) +{ + int ret_val = CLOCK_SUCCESS; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + gclk_registers_t *gclk_regs = config->gclk_regs; + uint8_t inst = subsys.bits.inst; + + __IO uint32_t *reg32 = NULL; + + switch (subsys.bits.type) { + case SUBSYS_TYPE_XOSC: + oscctrl_regs->OSCCTRL_XOSCCTRL &= ~(OSCCTRL_XOSCCTRL_ENABLE_Msk); + break; + case SUBSYS_TYPE_OSC48M: + oscctrl_regs->OSCCTRL_OSC48MCTRL &= ~(OSCCTRL_OSC48MCTRL_ENABLE_Msk); + break; + case SUBSYS_TYPE_FDPLL: + oscctrl_regs->OSCCTRL_DPLLCTRLA &= ~(OSCCTRL_DPLLCTRLA_ENABLE_Msk); + break; + case SUBSYS_TYPE_XOSC32K: + if (inst == INST_XOSC32K_XOSC1K) { + osc32kctrl_regs->OSC32KCTRL_XOSC32K &= ~(OSC32KCTRL_XOSC32K_EN1K_Msk); + } else { + osc32kctrl_regs->OSC32KCTRL_XOSC32K &= ~(OSC32KCTRL_XOSC32K_EN32K_Msk); + } + + if ((osc32kctrl_regs->OSC32KCTRL_XOSC32K & + (OSC32KCTRL_XOSC32K_EN1K_Msk | OSC32KCTRL_XOSC32K_EN32K_Msk)) == 0) { + /* turn off XOSC32K if both EN1K and EN32K are off */ + osc32kctrl_regs->OSC32KCTRL_XOSC32K &= ~OSC32KCTRL_XOSC32K_ENABLE_Msk; + } + break; + case SUBSYS_TYPE_OSC32K: + if (inst == INST_OSC32K_OSC1K) { + osc32kctrl_regs->OSC32KCTRL_OSC32K &= ~(OSC32KCTRL_OSC32K_EN1K_Msk); + } else { + osc32kctrl_regs->OSC32KCTRL_OSC32K &= ~(OSC32KCTRL_OSC32K_EN32K_Msk); + } + + if ((osc32kctrl_regs->OSC32KCTRL_OSC32K & + (OSC32KCTRL_OSC32K_EN1K_Msk | OSC32KCTRL_OSC32K_EN32K_Msk)) == 0) { + /* turn off OSC32K if both EN1K and EN32K are off */ + osc32kctrl_regs->OSC32KCTRL_OSC32K &= ~OSC32KCTRL_OSC32K_ENABLE_Msk; + } + break; + case SUBSYS_TYPE_GCLKGEN: + /* Check if the clock is GCLKGEN0, which is always on */ + if (inst == CLOCK_MCHP_GCLKGEN_GEN0) { + /* GCLK GEN0 is always on */ + break; + } + + /* Disable the clock generator by clearing the GENEN bit */ + gclk_regs->GCLK_GENCTRL[inst] &= ~(GCLK_GENCTRL_GENEN_Msk); + break; + case SUBSYS_TYPE_GCLKPERIPH: + gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] &= ~(GCLK_PCHCTRL_CHEN_Msk); + break; + case SUBSYS_TYPE_MCLKPERIPH: + reg32 = get_mclkbus_mask_reg(config->mclk_regs, subsys.bits.mclkbus); + *reg32 &= ~(1 << subsys.bits.mclkmaskbit); + break; + default: + ret_val = -ENOTSUP; + break; + } + + return ret_val; +} + +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE +/** + * @brief get rate of gclk generator in Hz. + */ +static int clock_get_rate_gclkgen(const struct device *dev, clock_mchp_gclkgen_t gclkgen_id, + clock_mchp_gclk_src_clock_t gclkgen_called_src, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + gclk_registers_t *gclk_regs = config->gclk_regs; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + clock_mchp_data_t *data = dev->data; + + clock_mchp_gclk_src_clock_t gclkgen_src; + uint32_t gclkgen_src_freq = 0, mask; + uint16_t gclkgen_div; + + bool power_div = (((gclk_regs->GCLK_GENCTRL[gclkgen_id] & GCLK_GENCTRL_DIVSEL_Msk) >> + GCLK_GENCTRL_DIVSEL_Pos) == GCLK_GENCTRL_DIVSEL_DIV1_Val) + ? false + : true; + + do { + /* Return rate as 0, if clock is not on */ + if (clock_mchp_get_status(dev, (clock_control_subsys_t)MCHP_CLOCK_DERIVE_ID( + SUBSYS_TYPE_GCLKGEN, MBUS_NA, MMASK_NA, + GPH_NA, gclkgen_id)) != + CLOCK_CONTROL_STATUS_ON) { + *freq = 0; + break; + } + + /* get source for gclk generator from gclkgen registers */ + gclkgen_src = (gclk_regs->GCLK_GENCTRL[gclkgen_id] & GCLK_GENCTRL_SRC_Msk) >> + GCLK_GENCTRL_SRC_Pos; + if (gclkgen_called_src == gclkgen_src) { + ret_val = -ENOTSUP; + break; + } + + switch (gclkgen_src) { + case CLOCK_MCHP_GCLK_SRC_XOSC: + gclkgen_src_freq = data->xosc_crystal_freq; + break; + + case CLOCK_MCHP_GCLK_SRC_OSC48M: + ret_val = clock_get_rate_osc48m(dev, &gclkgen_src_freq); + break; + + case CLOCK_MCHP_GCLK_SRC_FDPLL: + ret_val = clock_get_rate_fdpll(dev, &gclkgen_src_freq); + break; + + case CLOCK_MCHP_GCLK_SRC_OSCULP32K: + gclkgen_src_freq = FREQ_32KHZ; + break; + + case CLOCK_MCHP_GCLK_SRC_XOSC32K: + mask = OSC32KCTRL_XOSC32K_ENABLE_Msk | OSC32KCTRL_XOSC32K_EN32K_Msk; + gclkgen_src_freq = ((osc32kctrl_regs->OSC32KCTRL_XOSC32K & mask) == mask) + ? FREQ_32KHZ + : 0; + break; + + case CLOCK_MCHP_GCLK_SRC_OSC32K: + mask = OSC32KCTRL_OSC32K_ENABLE_Msk | OSC32KCTRL_OSC32K_EN32K_Msk; + gclkgen_src_freq = ((osc32kctrl_regs->OSC32KCTRL_OSC32K & mask) == mask) + ? FREQ_32KHZ + : 0; + break; + + case CLOCK_MCHP_GCLK_SRC_GCLKPIN: + if (gclkgen_id <= GCLK_IO_MAX) { + gclkgen_src_freq = data->gclkpin_freq[gclkgen_id]; + } else { + ret_val = -ENOTSUP; + } + break; + + case CLOCK_MCHP_GCLK_SRC_GCLKGEN1: + ret_val = (gclkgen_id == CLOCK_MCHP_GCLKGEN_GEN1) + ? -ELOOP + : clock_get_rate_gclkgen(dev, CLOCK_MCHP_GCLKGEN_GEN1, + CLOCK_MCHP_GCLK_SRC_MAX + 1, + &gclkgen_src_freq); + break; + default: + break; + } + if (ret_val != CLOCK_SUCCESS) { + break; + } + + /* get gclk generator clock divider*/ + gclkgen_div = (gclk_regs->GCLK_GENCTRL[gclkgen_id] & GCLK_GENCTRL_DIV_Msk) >> + GCLK_GENCTRL_DIV_Pos; + + /* + * For gclk1, 8 division factor bits - DIV[7:0] + * others, 16 division factor bits - DIV[15:0] + */ + if (gclkgen_id != CLOCK_MCHP_GCLKGEN_GEN1) { + gclkgen_div = gclkgen_div & 0xFF; + } + + if (power_div == true) { + if (gclkgen_div > GCLKGEN_POWER_DIV_MAX) { + gclkgen_div = GCLKGEN_POWER_DIV_MAX; + } + gclkgen_div = 1 << (gclkgen_div + 1); + } + + /* if DIV value is 0, has same effect as DIV value 1 */ + if (gclkgen_div == 0) { + gclkgen_div = 1; + } + *freq = gclkgen_src_freq / gclkgen_div; + } while (0); + + return ret_val; +} + +/** + * @brief get rate of OSC48M in Hz. + */ +static int clock_get_rate_osc48m(const struct device *dev, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + + uint8_t post_divider_freq; + const uint32_t post_divider_freq_array[] = { + 48000000, 24000000, 16000000, 12000000, 9600000, 8000000, 6860000, 6000000, + 5330000, 4800000, 4360000, 4000000, 3690000, 3430000, 3200000, 3000000}; + + if ((oscctrl_regs->OSCCTRL_STATUS & OSCCTRL_STATUS_OSC48MRDY_Msk) == 0) { + /* Return rate as 0, if clock is not on */ + *freq = 0; + } else { + post_divider_freq = (oscctrl_regs->OSCCTRL_OSC48MDIV & OSCCTRL_OSC48MDIV_DIV_Msk) >> + OSCCTRL_OSC48MDIV_DIV_Pos; + *freq = post_divider_freq_array[post_divider_freq]; + } + + return ret_val; +} + +/** + * @brief get rate of FDPLL in Hz. + */ +static int clock_get_rate_fdpll(const struct device *dev, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + clock_mchp_data_t *data = dev->data; + + uint32_t src_freq = 0, xosc_div, mult_int, mult_frac, frac_mult_max; + clock_mchp_gclkgen_t src_gclkgen; + uint8_t ref_clk_type, output_prescalar; + + do { + /* Return rate as 0, if clock is not on */ + if (clock_mchp_get_status(dev, (clock_control_subsys_t)MCHP_CLOCK_DERIVE_ID( + SUBSYS_TYPE_FDPLL, MBUS_NA, MMASK_NA, 0, + 0)) != CLOCK_CONTROL_STATUS_ON) { + *freq = 0; + break; + } + + /* Find the source clock */ + ref_clk_type = (oscctrl_regs->OSCCTRL_DPLLCTRLB & OSCCTRL_DPLLCTRLB_REFCLK_Msk) >> + OSCCTRL_DPLLCTRLB_REFCLK_Pos; + + /* Find the source clock frequency */ + switch (ref_clk_type) { + case OSCCTRL_DPLLCTRLB_REFCLK_XOSC32K_Val: + src_freq = FREQ_32KHZ; + break; + + case OSCCTRL_DPLLCTRLB_REFCLK_XOSC_Val: + xosc_div = (oscctrl_regs->OSCCTRL_DPLLCTRLB & OSCCTRL_DPLLCTRLB_DIV_Msk) >> + OSCCTRL_DPLLCTRLB_DIV_Pos; + src_freq = data->xosc_crystal_freq / (2 * (xosc_div + 1)); + break; + + case OSCCTRL_DPLLCTRLB_REFCLK_GCLK_Val: + src_gclkgen = (config->gclk_regs->GCLK_PCHCTRL[0] & GCLK_PCHCTRL_GEN_Msk) >> + GCLK_PCHCTRL_GEN_Pos; + ret_val = clock_get_rate_gclkgen(dev, src_gclkgen, + CLOCK_MCHP_GCLK_SRC_FDPLL, &src_freq); + break; + default: + break; + } + if (ret_val != CLOCK_SUCCESS) { + break; + } + + /* Multiply by integer & fractional part multipliers */ + mult_int = (oscctrl_regs->OSCCTRL_DPLLRATIO & OSCCTRL_DPLLRATIO_LDR_Msk) >> + OSCCTRL_DPLLRATIO_LDR_Pos; + mult_frac = (oscctrl_regs->OSCCTRL_DPLLRATIO & OSCCTRL_DPLLRATIO_LDRFRAC_Msk) >> + OSCCTRL_DPLLRATIO_LDRFRAC_Pos; + + frac_mult_max = OSCCTRL_DPLLRATIO_LDRFRAC_Msk >> OSCCTRL_DPLLRATIO_LDRFRAC_Pos; + *freq = (src_freq * (((mult_int + 1) * (frac_mult_max + 1)) + mult_frac)) / + (frac_mult_max + 1); + + /* Divide by output prescalar value */ + output_prescalar = + (oscctrl_regs->OSCCTRL_DPLLPRESC & OSCCTRL_DPLLPRESC_PRESC_Msk) >> + OSCCTRL_DPLLPRESC_PRESC_Pos; + *freq = *freq / (1 << output_prescalar); + } while (0); + + return ret_val; +} + +/** + * @brief get rate of RTC in Hz. + */ +static int clock_get_rate_rtc(const struct device *dev, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + + uint8_t rtc_src; + uint32_t mask; + + /* get rtc source clock*/ + rtc_src = (config->osc32kctrl_regs->OSC32KCTRL_RTCCTRL & OSC32KCTRL_RTCCTRL_RTCSEL_Msk) >> + OSC32KCTRL_RTCCTRL_RTCSEL_Pos; + + switch (rtc_src) { + case OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K_Val: + *freq = FREQ_1KHZ; + break; + + case OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K_Val: + *freq = FREQ_32KHZ; + break; + + case OSC32KCTRL_RTCCTRL_RTCSEL_OSC1K_Val: + mask = OSC32KCTRL_OSC32K_ENABLE_Msk | OSC32KCTRL_OSC32K_EN1K_Msk; + *freq = ((osc32kctrl_regs->OSC32KCTRL_OSC32K & mask) == mask) ? FREQ_1KHZ : 0; + break; + + case OSC32KCTRL_RTCCTRL_RTCSEL_OSC32K_Val: + mask = OSC32KCTRL_OSC32K_ENABLE_Msk | OSC32KCTRL_OSC32K_EN32K_Msk; + *freq = ((osc32kctrl_regs->OSC32KCTRL_OSC32K & mask) == mask) ? FREQ_32KHZ : 0; + break; + + case OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K_Val: + mask = OSC32KCTRL_XOSC32K_ENABLE_Msk | OSC32KCTRL_XOSC32K_EN1K_Msk; + *freq = ((osc32kctrl_regs->OSC32KCTRL_XOSC32K & mask) == mask) ? FREQ_1KHZ : 0; + break; + + case OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K_Val: + mask = OSC32KCTRL_XOSC32K_ENABLE_Msk | OSC32KCTRL_XOSC32K_EN32K_Msk; + *freq = ((osc32kctrl_regs->OSC32KCTRL_XOSC32K & mask) == mask) ? FREQ_32KHZ : 0; + break; + + default: + ret_val = -ENOTSUP; + } + + return ret_val; +} +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ + +/****************************************************************************** + * @brief API functions + *****************************************************************************/ + +/** + * @brief Turn on the clock for a specified subsystem, can be blocking. + * + * @param dev Pointer to the clock device structure + * @param sys Clock subsystem + * + * @return 0 if the clock is successfully turned on + * @return -ENOTSUP If the requested operation is not supported. + * @return -ETIMEDOUT If the requested operation is timedout. + * @return -EALREADY If clock is already on. + */ +static int clock_mchp_on(const struct device *dev, clock_control_subsys_t sys) +{ + int ret_val = -ENOTSUP; + const clock_mchp_config_t *config = dev->config; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + + enum clock_control_status status; + uint32_t on_timeout_ms = 0; + bool is_wait = false; + + /* Validate subsystem. */ + if (CLOCK_SUCCESS == clock_check_subsys(subsys)) { + status = clock_mchp_get_status(dev, sys); + if (status == CLOCK_CONTROL_STATUS_ON) { + /* clock is already on. */ + ret_val = -EALREADY; + + } else { + if (clock_on(config, subsys) == CLOCK_SUCCESS) { + /* clock on operation is successful. */ + is_wait = true; + } + } + } + + /* Wait until the clock state becomes ON. */ + while (is_wait == true) { + /* For OSC32K, need to wait for the oscillator to be on. get_status only + * return if EN1K or EN32K is on, which does not indicate the status of + * OSC32K + */ + if (subsys.bits.type == SUBSYS_TYPE_XOSC32K) { + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + + if ((osc32kctrl_regs->OSC32KCTRL_STATUS & + OSC32KCTRL_STATUS_XOSC32KRDY_Msk) != 0) { + /* Successfully turned on clock. */ + ret_val = CLOCK_SUCCESS; + break; + } + } else if (subsys.bits.type == SUBSYS_TYPE_OSC32K) { + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + + if ((osc32kctrl_regs->OSC32KCTRL_STATUS & + OSC32KCTRL_STATUS_OSC32KRDY_Msk) != 0) { + /* Successfully turned on clock. */ + ret_val = CLOCK_SUCCESS; + break; + } + } else { + status = clock_mchp_get_status(dev, sys); + if (status == CLOCK_CONTROL_STATUS_ON) { + /* Successfully turned on clock. */ + ret_val = CLOCK_SUCCESS; + break; + } + } + + if (on_timeout_ms < config->on_timeout_ms) { + /* Thread is not available while booting. */ + if ((k_is_pre_kernel() == false) && (k_current_get() != NULL)) { + /* Sleep before checking again. */ + k_sleep(K_MSEC(1)); + on_timeout_ms++; + } + } else { + /* Clock on timeout occurred */ + ret_val = -ETIMEDOUT; + break; + } + } + + return ret_val; +} + +/** + * @brief Turn off the clock for a specified subsystem. + * + * @param dev Pointer to the clock device structure + * @param sys Clock subsystem + * + * @return 0 if the clock is successfully turned off + * @return -ENOTSUP If the requested operation is not supported. + * @return -EALREADY If clock is already off. + */ +static int clock_mchp_off(const struct device *dev, clock_control_subsys_t sys) +{ + int ret_val = -ENOTSUP; + const clock_mchp_config_t *config = dev->config; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + + do { + /* Validate subsystem. */ + if (CLOCK_SUCCESS != clock_check_subsys(subsys)) { + break; + } + + ret_val = clock_off(config, subsys); + } while (0); + + return ret_val; +} + +/** + * @brief Get the status of clock, for a specified subsystem. + * + * This function retrieves the current status of the clock for a given subsystem. + * + * @param dev Pointer to the clock device structure. + * @param sys The clock subsystem. + * + * @return The current status of clock for the subsystem (e.g., off, on, starting, or + * unknown). + */ +static enum clock_control_status clock_mchp_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + enum clock_control_status ret_status = CLOCK_CONTROL_STATUS_UNKNOWN; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + + /* Validate subsystem. */ + if (CLOCK_SUCCESS == clock_check_subsys(subsys)) { + ret_status = clock_get_status(dev, sys); + } + + /* Return the status of the clock for the specified subsystem. */ + return ret_status; +} + +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE +/** + * @brief Get the rate of the clock for a specified subsystem. + * + * This function retrieves the clock frequency (Hz) for the given subsystem. + * + * @param dev Pointer to clock device structure. + * @param sys The clock subsystem. + * @param frequency Pointer to store the retrieved clock rate. + * + * @return 0 if the rate is successfully retrieved. + * @return -ENOTSUP If the requested operation is not supported. + */ +static int clock_mchp_get_rate(const struct device *dev, clock_control_subsys_t sys, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + clock_mchp_data_t *data = dev->data; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + uint8_t inst = subsys.bits.inst; + + uint8_t cpu_div; + uint32_t gclkgen_src_freq = 0; + clock_mchp_gclkgen_t gclkperiph_src; + + do { + /* Validate subsystem. */ + if (CLOCK_SUCCESS != clock_check_subsys(subsys)) { + ret_val = -ENOTSUP; + break; + } + + /* Return rate as 0, if clock is not on */ + if (clock_mchp_get_status(dev, sys) != CLOCK_CONTROL_STATUS_ON) { + *freq = 0; + break; + } + + switch (subsys.bits.type) { + case SUBSYS_TYPE_XOSC: + *freq = data->xosc_crystal_freq; + break; + + case SUBSYS_TYPE_OSC48M: + ret_val = clock_get_rate_osc48m(dev, freq); + break; + + case SUBSYS_TYPE_FDPLL: + ret_val = clock_get_rate_fdpll(dev, freq); + break; + + case SUBSYS_TYPE_RTC: + ret_val = clock_get_rate_rtc(dev, freq); + break; + + case SUBSYS_TYPE_XOSC32K: + if (inst == INST_XOSC32K_XOSC1K) { + *freq = FREQ_1KHZ; + + } else { + *freq = FREQ_32KHZ; + } + break; + + case SUBSYS_TYPE_OSC32K: + if (inst == INST_OSC32K_OSC1K) { + *freq = FREQ_1KHZ; + + } else { + *freq = FREQ_32KHZ; + } + break; + + case SUBSYS_TYPE_GCLKGEN: + ret_val = clock_get_rate_gclkgen(dev, inst, CLOCK_MCHP_GCLK_SRC_MAX + 1, + freq); + break; + + case SUBSYS_TYPE_GCLKPERIPH: + gclkperiph_src = (config->gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] & + GCLK_PCHCTRL_GEN_Msk) >> + GCLK_PCHCTRL_GEN_Pos; + ret_val = clock_get_rate_gclkgen(dev, gclkperiph_src, + CLOCK_MCHP_GCLK_SRC_MAX + 1, freq); + break; + + case SUBSYS_TYPE_MCLKCPU: + case SUBSYS_TYPE_MCLKPERIPH: + /* source for mclk is always gclk0 */ + ret_val = clock_get_rate_gclkgen(dev, 0, CLOCK_MCHP_GCLK_SRC_MAX + 1, + &gclkgen_src_freq); + if (ret_val == CLOCK_SUCCESS) { + cpu_div = + (config->mclk_regs->MCLK_CPUDIV & MCLK_CPUDIV_CPUDIV_Msk) >> + MCLK_CPUDIV_CPUDIV_Pos; + if (cpu_div != 0) { + *freq = gclkgen_src_freq / cpu_div; + } + } + break; + default: + ret_val = -ENOTSUP; + break; + } + + } while (0); + + return ret_val; +} + +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ + +#if CONFIG_CLOCK_CONTROL_MCHP_CONFIG_RUNTIME +/** + * @brief Configure the clock for a specified subsystem. + * + * req_config is typecasted to corresponding structure type, according to the clock + * subsystem. + * + * @param dev Pointer to clock device structure. + * @param sys The clock subsystem. + * @param req_config Pointer to the requested configuration for the clock. + * + * @return 0 if the configuration is successful. + * @return -EINVAL if req_config is not a valid value. + * @return -ENOTSUP If the requested operation is not supported. + */ +static int clock_mchp_configure(const struct device *dev, clock_control_subsys_t sys, + void *req_config) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + gclk_registers_t *gclk_regs = config->gclk_regs; + clock_mchp_subsys_t subsys; + + subsys.val = (uint32_t)sys; + uint16_t inst = subsys.bits.inst; + + uint32_t val32 = 0; + uint16_t val16 = 0; + uint8_t val8 = 0; + + do { + if (req_config == NULL) { + ret_val = -EINVAL; + break; + } + /* Validate subsystem. */ + if (CLOCK_SUCCESS != clock_check_subsys(subsys)) { + ret_val = -ENOTSUP; + break; + } + + switch (subsys.bits.type) { + case SUBSYS_TYPE_XOSC: + clock_mchp_subsys_xosc_config_t *xosc_config = + (clock_mchp_subsys_xosc_config_t *)req_config; + val16 = oscctrl_regs->OSCCTRL_XOSCCTRL; + val16 &= ~(OSCCTRL_XOSCCTRL_RUNSTDBY_Msk | OSCCTRL_XOSCCTRL_ONDEMAND_Msk); + val16 |= ((xosc_config->run_in_standby_en != 0) + ? OSCCTRL_XOSCCTRL_RUNSTDBY(1) + : 0); + val16 |= ((xosc_config->on_demand_en != 0) ? OSCCTRL_XOSCCTRL_ONDEMAND(1) + : 0); + oscctrl_regs->OSCCTRL_XOSCCTRL = val16; + break; + + case SUBSYS_TYPE_OSC48M: + clock_mchp_subsys_osc48m_config_t *osc48m_config = + (clock_mchp_subsys_osc48m_config_t *)req_config; + /* Configure on_demand_en and run_in_standby_en */ + val8 = oscctrl_regs->OSCCTRL_OSC48MCTRL; + val8 &= ~(OSCCTRL_OSC48MCTRL_RUNSTDBY_Msk | + OSCCTRL_OSC48MCTRL_ONDEMAND_Msk); + val8 |= ((osc48m_config->run_in_standby_en != 0) + ? OSCCTRL_OSC48MCTRL_RUNSTDBY(1) + : 0); + val8 |= ((osc48m_config->on_demand_en != 0) ? OSCCTRL_OSC48MCTRL_ONDEMAND(1) + : 0); + oscctrl_regs->OSCCTRL_OSC48MCTRL = val8; + + /* Configure post_divider_freq */ + if (osc48m_config->post_divider_freq <= CLOCK_MCHP_DIVIDER_3_MHZ) { + val8 = oscctrl_regs->OSCCTRL_OSC48MDIV; + val8 &= ~(OSCCTRL_OSC48MDIV_DIV_Msk); + val8 |= osc48m_config->post_divider_freq; + oscctrl_regs->OSCCTRL_OSC48MDIV = val8; + } else { + LOG_ERR("Unsupported OSC48M post_divider_freq"); + } + break; + + case SUBSYS_TYPE_FDPLL: + clock_mchp_subsys_fdpll_config_t *fdpll_config = + (clock_mchp_subsys_fdpll_config_t *)req_config; + + val32 = oscctrl_regs->OSCCTRL_DPLLCTRLB; + if (fdpll_config->src <= CLOCK_MCHP_FDPLL_SRC_XOSC) { + val32 &= ~OSCCTRL_DPLLCTRLB_REFCLK_Msk; + switch (fdpll_config->src) { + case CLOCK_MCHP_FDPLL_SRC_XOSC32K: + val32 |= OSCCTRL_DPLLCTRLB_REFCLK_XOSC32K; + break; + + case CLOCK_MCHP_FDPLL_SRC_XOSC: + val32 |= OSCCTRL_DPLLCTRLB_REFCLK_XOSC; + break; + + default: + val32 |= OSCCTRL_DPLLCTRLB_REFCLK_GCLK; + /* source is gclk*/ + gclk_regs->GCLK_PCHCTRL[inst + 1] &= ~GCLK_PCHCTRL_GEN_Msk; + gclk_regs->GCLK_PCHCTRL[inst + 1] |= + GCLK_PCHCTRL_GEN(fdpll_config->src); + break; + } + } else { + LOG_ERR("Unsupported FDPLL source clock"); + } + + val32 &= ~OSCCTRL_DPLLCTRLB_DIV_Msk; + val32 |= OSCCTRL_DPLLCTRLB_DIV(fdpll_config->xosc_clock_divider); + oscctrl_regs->OSCCTRL_DPLLCTRLB = val32; + + /* DPLLRATIO */ + val32 = oscctrl_regs->OSCCTRL_DPLLRATIO; + val32 &= ~(OSCCTRL_DPLLRATIO_LDRFRAC_Msk | OSCCTRL_DPLLRATIO_LDR_Msk); + val32 |= OSCCTRL_DPLLRATIO_LDRFRAC(fdpll_config->divider_ratio_frac); + val32 |= OSCCTRL_DPLLRATIO_LDR(fdpll_config->divider_ratio_int); + oscctrl_regs->OSCCTRL_DPLLRATIO = val32; + + /* DPLLCTRLA */ + val8 = oscctrl_regs->OSCCTRL_DPLLCTRLA; + val8 &= ~(OSCCTRL_DPLLCTRLA_RUNSTDBY_Msk | OSCCTRL_DPLLCTRLA_ONDEMAND_Msk); + val8 |= ((fdpll_config->run_in_standby_en != 0) + ? OSCCTRL_DPLLCTRLA_RUNSTDBY(1) + : 0); + val8 |= ((fdpll_config->on_demand_en != 0) ? OSCCTRL_DPLLCTRLA_ONDEMAND(1) + : 0); + oscctrl_regs->OSCCTRL_DPLLCTRLA = val8; + break; + + case SUBSYS_TYPE_RTC: + clock_mchp_subsys_rtc_config_t *rtc_config = + (clock_mchp_subsys_rtc_config_t *)req_config; + osc32kctrl_regs->OSC32KCTRL_RTCCTRL = + OSC32KCTRL_RTCCTRL_RTCSEL(rtc_config->src); + break; + + case SUBSYS_TYPE_XOSC32K: + clock_mchp_subsys_xosc32k_config_t *xosc32k_config = + (clock_mchp_subsys_xosc32k_config_t *)req_config; + + val16 = osc32kctrl_regs->OSC32KCTRL_XOSC32K; + val16 &= ~(OSC32KCTRL_XOSC32K_RUNSTDBY_Msk | + OSC32KCTRL_XOSC32K_ONDEMAND_Msk); + val16 |= ((xosc32k_config->run_in_standby_en != 0) + ? OSC32KCTRL_XOSC32K_RUNSTDBY(1) + : 0); + val16 |= ((xosc32k_config->on_demand_en != 0) + ? OSC32KCTRL_XOSC32K_ONDEMAND(1) + : 0); + + osc32kctrl_regs->OSC32KCTRL_XOSC32K = val16; + break; + + case SUBSYS_TYPE_OSC32K: + clock_mchp_subsys_osc32k_config_t *osc32k_config = + (clock_mchp_subsys_osc32k_config_t *)req_config; + + val32 = osc32kctrl_regs->OSC32KCTRL_OSC32K; + val32 &= ~(OSC32KCTRL_OSC32K_RUNSTDBY_Msk | OSC32KCTRL_OSC32K_ONDEMAND_Msk); + val32 |= ((osc32k_config->run_in_standby_en != 0) + ? OSC32KCTRL_OSC32K_RUNSTDBY(1) + : 0); + val32 |= ((osc32k_config->on_demand_en != 0) ? OSC32KCTRL_OSC32K_ONDEMAND(1) + : 0); + osc32kctrl_regs->OSC32KCTRL_OSC32K = val32; + break; + + case SUBSYS_TYPE_GCLKGEN: + clock_mchp_subsys_gclkgen_config_t *gclkgen_config = + (clock_mchp_subsys_gclkgen_config_t *)req_config; + + val32 = gclk_regs->GCLK_GENCTRL[inst]; + val32 &= ~(GCLK_GENCTRL_RUNSTDBY_Msk | GCLK_GENCTRL_SRC_Msk | + GCLK_GENCTRL_DIV_Msk); + val32 |= + ((gclkgen_config->run_in_standby_en != 0) ? GCLK_GENCTRL_RUNSTDBY(1) + : 0); + + val32 |= GCLK_GENCTRL_SRC(gclkgen_config->src); + /* check range for div_factor, gclk1: 0 - 65535, others: 0 - 255 */ + if ((inst == CLOCK_MCHP_GCLKGEN_GEN1) || + (gclkgen_config->div_factor <= 0xFF)) { + val32 |= GCLK_GENCTRL_DIV(gclkgen_config->div_factor); + } + + gclk_regs->GCLK_GENCTRL[inst] = val32; + break; + + case SUBSYS_TYPE_GCLKPERIPH: + clock_mchp_subsys_gclkperiph_config_t *gclkperiph_config = + (clock_mchp_subsys_gclkperiph_config_t *)req_config; + val32 = gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph]; + val32 &= ~GCLK_PCHCTRL_GEN_Msk; + val32 |= GCLK_PCHCTRL_GEN(gclkperiph_config->src); + gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] = val32; + break; + + case SUBSYS_TYPE_MCLKCPU: + clock_mchp_subsys_mclkcpu_config_t *mclkcpu_config = + (clock_mchp_subsys_mclkcpu_config_t *)req_config; + config->mclk_regs->MCLK_CPUDIV = + MCLK_CPUDIV_CPUDIV(mclkcpu_config->division_factor); + break; + + default: + ret_val = -ENOTSUP; + break; + } + } while (0); + + return ret_val; +} +#endif /* CONFIG_CLOCK_CONTROL_MCHP_CONFIG_RUNTIME */ + +#if CONFIG_CLOCK_CONTROL_MCHP_CONFIG_BOOTUP +/****************************************************************************** + * @brief Internal initialization functions + *****************************************************************************/ +/** + * @brief initialize XOSC from device tree node. + */ +void clock_xosc_init(const struct device *dev, clock_xosc_init_t *xosc_init) +{ + const clock_mchp_config_t *config = dev->config; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + clock_mchp_data_t *data = dev->data; + + uint16_t val16; + + /* Check if xosc clock is already on */ + if ((data->fdpll_src_on_status & (1 << CLOCK_MCHP_FDPLL_SRC_XOSC)) == 0) { + data->xosc_crystal_freq = xosc_init->frequency; + + /* XOSCCTRL */ + val16 = 0; + val16 |= OSCCTRL_XOSCCTRL_STARTUP(xosc_init->startup_time); + val16 |= ((xosc_init->automatic_amplitude_gain_control_en != 0) + ? OSCCTRL_XOSCCTRL_AMPGC(1) + : 0); + /* Important: Initializing it with 1, along with clock enabled, can lead to + * indefinite wait for the clock to be on, if there is no peripheral request + * for the clock in the sequence of clock Initialization. If required, + * better to turn on the clock using API, instead of enabling both + * (on_demand_en & enable) during startup. + */ + val16 |= ((xosc_init->on_demand_en != 0) ? OSCCTRL_XOSCCTRL_ONDEMAND(1) : 0); + val16 |= ((xosc_init->run_in_standby_en != 0) ? OSCCTRL_XOSCCTRL_RUNSTDBY(1) : 0); + + val16 |= ((xosc_init->clock_failure_detection_en != 0) ? OSCCTRL_XOSCCTRL_CFDEN(1) + : 0); + val16 |= OSCCTRL_XOSCCTRL_GAIN(CLOCK_OSCCTRL_XOSCCTRL_GAIN_VALUE); + + val16 |= ((xosc_init->xtal_en != 0) ? OSCCTRL_XOSCCTRL_XTALEN(1) : 0); + val16 |= ((xosc_init->enable != 0) ? OSCCTRL_XOSCCTRL_ENABLE(1) : 0); + + oscctrl_regs->OSCCTRL_XOSCCTRL = val16; + if (xosc_init->enable != 0) { + while ((oscctrl_regs->OSCCTRL_STATUS & OSCCTRL_STATUS_XOSCRDY_Msk) == 0) { + } + + /* Set xosc clock as on */ + data->fdpll_src_on_status |= 1 << CLOCK_MCHP_FDPLL_SRC_XOSC; + data->gclkgen_src_on_status |= 1 << CLOCK_MCHP_GCLK_SRC_XOSC; + } + } +} + +/** + * @brief initialize OSC48M from device tree node. + */ +void clock_osc48m_init(const struct device *dev, clock_osc48m_init_t *osc48m_init) +{ + const clock_mchp_config_t *config = dev->config; + clock_mchp_data_t *data = dev->data; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + + uint8_t val8; + + do { + /* Check if osc48m clock is already on */ + if ((data->gclkgen_src_on_status & (1 << CLOCK_MCHP_GCLK_SRC_OSC48M)) != 0) { + break; + } + + /* To avoid changing osc48m, while gclk0 is driven by it. Else will affect CPU */ + if (data->gclk0_src == CLOCK_MCHP_GCLK_SRC_OSC48M) { + break; + } + + /* OSC48MDIV */ + val8 = 0; + val8 |= OSCCTRL_OSC48MDIV_DIV(osc48m_init->post_divider_freq); + + oscctrl_regs->OSCCTRL_OSC48MDIV = val8; + while (oscctrl_regs->OSCCTRL_OSC48MSYNCBUSY) { + } + + /* OSC48MCTRL */ + val8 = 0; + + /* Important: Initializing it with 1, along with clock enabled, can lead to + * indefinite wait for the clock to be on, if there is no peripheral request + * for the clock in the sequence of clock Initialization. If required, + * better to turn on the clock using API, instead of enabling both + * (on_demand_en & enable) during startup. + */ + val8 |= ((osc48m_init->on_demand_en != 0) ? OSCCTRL_OSC48MCTRL_ONDEMAND(1) : 0); + val8 |= ((osc48m_init->run_in_standby_en != 0) ? OSCCTRL_OSC48MCTRL_RUNSTDBY(1) + : 0); + val8 |= ((osc48m_init->enable != 0) ? OSCCTRL_OSC48MCTRL_ENABLE(1) : 0); + + oscctrl_regs->OSCCTRL_OSC48MCTRL = val8; + if (osc48m_init->enable != 0) { + while ((oscctrl_regs->OSCCTRL_STATUS & OSCCTRL_STATUS_OSC48MRDY_Msk) == 0) { + } + data->gclkgen_src_on_status |= (1 << CLOCK_MCHP_GCLK_SRC_OSC48M); + } + } while (0); +} + +/** + * @brief initialize FDPLL from device tree node. + */ +void clock_fdpll_init(const struct device *dev, clock_fdpll_init_t *fdpll_init) +{ + const clock_mchp_config_t *config = dev->config; + clock_mchp_data_t *data = dev->data; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + gclk_registers_t *gclk_regs = config->gclk_regs; + + uint8_t val8; + int src; + uint32_t val32, mask; + + /* Check if fdpll clock is already on */ + if (data->gclkgen_src_on_status & (1 << (CLOCK_MCHP_GCLK_SRC_FDPLL))) { + /* Early error handling return for code readability and maintainability */ + return; + } + + /* Check if source clock of fdpll is off */ + src = fdpll_init->src; + if ((data->fdpll_src_on_status & (1 << src)) == 0) { + /* Early error handling return for code readability and maintainability */ + return; + } + + /* program gclkph if source is gclk & enable */ + if (src <= CLOCK_MCHP_FDPLL_SRC_GCLK8) { + gclk_regs->GCLK_PCHCTRL[0] |= (GCLK_PCHCTRL_GEN(src) | GCLK_PCHCTRL_CHEN_Msk); + while ((gclk_regs->GCLK_PCHCTRL[0] & GCLK_PCHCTRL_CHEN_Msk) == 0) { + } + } + + /* DPLLPRESC */ + val8 = oscctrl_regs->OSCCTRL_DPLLPRESC; + val8 &= ~OSCCTRL_DPLLPRESC_PRESC_Msk; + val8 |= OSCCTRL_DPLLPRESC_PRESC(fdpll_init->output_prescalar); + oscctrl_regs->OSCCTRL_DPLLPRESC = val8; + while (oscctrl_regs->OSCCTRL_DPLLSYNCBUSY) { + } + + /* DPLLCTRLB */ + val32 = oscctrl_regs->OSCCTRL_DPLLCTRLB; + val32 &= ~(OSCCTRL_DPLLCTRLB_DIV_Msk | OSCCTRL_DPLLCTRLB_LBYPASS_Msk | + OSCCTRL_DPLLCTRLB_REFCLK_Msk | OSCCTRL_DPLLCTRLB_WUF_Msk | + OSCCTRL_DPLLCTRLB_LPEN_Msk | OSCCTRL_DPLLCTRLB_FILTER_Msk); + val32 |= OSCCTRL_DPLLCTRLB_DIV(fdpll_init->xosc_clock_divider); + val32 |= ((fdpll_init->lock_bypass_en != 0) ? OSCCTRL_DPLLCTRLB_LBYPASS(1) : 0); + if (src > CLOCK_MCHP_FDPLL_SRC_GCLK8) { + val32 |= OSCCTRL_DPLLCTRLB_REFCLK((src == CLOCK_MCHP_FDPLL_SRC_XOSC32K) + ? OSCCTRL_DPLLCTRLB_REFCLK_XOSC32K_Val + : OSCCTRL_DPLLCTRLB_REFCLK_XOSC_Val); + } else { + val32 |= OSCCTRL_DPLLCTRLB_REFCLK(OSCCTRL_DPLLCTRLB_REFCLK_GCLK_Val); + } + val32 |= ((fdpll_init->wakeup_fast_en != 0) ? OSCCTRL_DPLLCTRLB_WUF(1) : 0); + val32 |= ((fdpll_init->low_power_en != 0) ? OSCCTRL_DPLLCTRLB_LPEN(1) : 0); + val32 |= OSCCTRL_DPLLCTRLB_FILTER(fdpll_init->pi_filter_type); + oscctrl_regs->OSCCTRL_DPLLCTRLB = val32; + + /* DPLLRATIO */ + val32 = oscctrl_regs->OSCCTRL_DPLLRATIO; + val32 &= ~(OSCCTRL_DPLLRATIO_LDRFRAC_Msk | OSCCTRL_DPLLRATIO_LDR_Msk); + val32 |= OSCCTRL_DPLLRATIO_LDRFRAC(fdpll_init->divider_ratio_frac); + val32 |= OSCCTRL_DPLLRATIO_LDR(fdpll_init->divider_ratio_int); + oscctrl_regs->OSCCTRL_DPLLRATIO = val32; + + while (oscctrl_regs->OSCCTRL_DPLLSYNCBUSY) { + } + + /* DPLLCTRLA */ + val8 = oscctrl_regs->OSCCTRL_DPLLCTRLA; + val8 &= ~(OSCCTRL_DPLLCTRLA_ONDEMAND_Msk | OSCCTRL_DPLLCTRLA_RUNSTDBY_Msk | + OSCCTRL_DPLLCTRLA_ENABLE_Msk); + + /* Important: Initializing it with 1, along with clock enabled, can lead to + * indefinite wait for the clock to be on, if there is no peripheral request + * for the clock in the sequence of clock Initialization. If required, + * better to turn on the clock using API, instead of enabling both + * (on_demand_en & enable) during startup. + */ + val8 |= ((fdpll_init->on_demand_en != 0) ? OSCCTRL_DPLLCTRLA_ONDEMAND(1) : 0); + val8 |= ((fdpll_init->run_in_standby_en != 0) ? OSCCTRL_DPLLCTRLA_RUNSTDBY(1) : 0); + val8 |= ((fdpll_init->enable != 0) ? OSCCTRL_DPLLCTRLA_ENABLE(1) : 0); + + oscctrl_regs->OSCCTRL_DPLLCTRLA = val8; + while (oscctrl_regs->OSCCTRL_DPLLSYNCBUSY) { + } + if (fdpll_init->enable != 0) { + mask = OSCCTRL_DPLLSTATUS_LOCK_Msk | OSCCTRL_DPLLSTATUS_CLKRDY_Msk; + while ((oscctrl_regs->OSCCTRL_DPLLSTATUS & mask) != mask) { + } + data->gclkgen_src_on_status |= (1 << CLOCK_MCHP_GCLK_SRC_FDPLL); + } +} + +/** + * @brief initialize rtc clock source from device tree node. + */ +void clock_rtc_init(const struct device *dev, uint8_t rtc_src) +{ + const clock_mchp_config_t *config = dev->config; + + config->osc32kctrl_regs->OSC32KCTRL_RTCCTRL = OSC32KCTRL_RTCCTRL_RTCSEL(rtc_src); +} + +/** + * @brief initialize xosc32k clocks from device tree node. + */ +void clock_xosc32k_init(const struct device *dev, clock_xosc32k_init_t *xosc32k_init) +{ + const clock_mchp_config_t *config = dev->config; + clock_mchp_data_t *data = dev->data; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + + uint8_t val8; + uint16_t val16; + + /* Check if xosc32k clock is already on */ + if ((data->gclkgen_src_on_status & (1 << CLOCK_MCHP_GCLK_SRC_XOSC32K)) == 0) { + /* CFDCTRL */ + val8 = 0; + val8 |= ((xosc32k_init->cfd_en != 0) ? OSC32KCTRL_CFDCTRL_CFDEN(1) : 0); + + osc32kctrl_regs->OSC32KCTRL_CFDCTRL = val8; + + /* XOSC32K */ + val16 = 0; + val16 |= OSC32KCTRL_XOSC32K_STARTUP(xosc32k_init->startup_time); + + /* Important: Initializing it with 1, along with clock enabled, can lead to + * indefinite wait for the clock to be on, if there is no peripheral request + * for the clock in the sequence of clock Initialization. If required, + * better to turn on the clock using API, instead of enabling both + * (on_demand_en & enable) during startup. + */ + val16 |= ((xosc32k_init->on_demand_en != 0) ? OSC32KCTRL_XOSC32K_ONDEMAND(1) : 0); + val16 |= ((xosc32k_init->run_in_standby_en != 0) ? OSC32KCTRL_XOSC32K_RUNSTDBY(1) + : 0); + val16 |= ((xosc32k_init->xosc32k_1khz_en != 0) ? OSC32KCTRL_XOSC32K_EN1K(1) : 0); + val16 |= ((xosc32k_init->xosc32k_32khz_en != 0) ? OSC32KCTRL_XOSC32K_EN32K(1) : 0); + val16 |= ((xosc32k_init->xtal_en != 0) ? OSC32KCTRL_XOSC32K_XTALEN(1) : 0); + val16 |= ((xosc32k_init->enable != 0) ? OSC32KCTRL_XOSC32K_ENABLE(1) : 0); + + osc32kctrl_regs->OSC32KCTRL_XOSC32K = val16; + + if (xosc32k_init->enable != 0) { + if ((xosc32k_init->xosc32k_32khz_en != 0) || + (xosc32k_init->xosc32k_1khz_en != 0)) { + while ((osc32kctrl_regs->OSC32KCTRL_STATUS & + OSC32KCTRL_STATUS_XOSC32KRDY_Msk) == 0) { + } + data->fdpll_src_on_status |= 1 << CLOCK_MCHP_FDPLL_SRC_XOSC32K; + data->gclkgen_src_on_status |= 1 << CLOCK_MCHP_GCLK_SRC_XOSC32K; + } + } + } +} + +/** + * @brief initialize osc32k clocks from device tree node. + */ +void clock_osc32k_init(const struct device *dev, clock_osc32k_init_t *osc32k_init) +{ + const clock_mchp_config_t *config = dev->config; + clock_mchp_data_t *data = dev->data; + osc32kctrl_registers_t *osc32kctrl_regs = config->osc32kctrl_regs; + + uint32_t val32; + + /* Check if osc32k clock is already on */ + if ((data->gclkgen_src_on_status & (1 << CLOCK_MCHP_GCLK_SRC_OSC32K)) == 0) { + /* OSC32K */ + val32 = 0; + val32 |= OSC32KCTRL_OSC32K_STARTUP(osc32k_init->startup_time); + + /* Important: Initializing it with 1, along with clock enabled, can lead to + * indefinite wait for the clock to be on, if there is no peripheral request + * for the clock in the sequence of clock Initialization. If required, + * better to turn on the clock using API, instead of enabling both + * (on_demand_en & enable) during startup. + */ + val32 |= ((osc32k_init->on_demand_en != 0) ? OSC32KCTRL_OSC32K_ONDEMAND(1) : 0); + val32 |= + ((osc32k_init->run_in_standby_en != 0) ? OSC32KCTRL_OSC32K_RUNSTDBY(1) : 0); + val32 |= ((osc32k_init->osc32k_1khz_en != 0) ? OSC32KCTRL_OSC32K_EN1K(1) : 0); + val32 |= ((osc32k_init->osc32k_32khz_en != 0) ? OSC32KCTRL_OSC32K_EN32K(1) : 0); + val32 |= ((osc32k_init->enable != 0) ? OSC32KCTRL_OSC32K_ENABLE(1) : 0); + + osc32kctrl_regs->OSC32KCTRL_OSC32K = val32; + + if (osc32k_init->enable != 0) { + if ((osc32k_init->osc32k_32khz_en != 0) || + (osc32k_init->osc32k_1khz_en != 0)) { + while ((osc32kctrl_regs->OSC32KCTRL_STATUS & + OSC32KCTRL_STATUS_OSC32KRDY_Msk) == 0) { + } + data->gclkgen_src_on_status |= 1 << CLOCK_MCHP_GCLK_SRC_OSC32K; + } + } + } +} + +/** + * @brief initialize gclk generator from device tree node. + */ +void clock_gclkgen_init(const struct device *dev, clock_gclkgen_init_t *gclkgen_init) +{ + const clock_mchp_config_t *config = dev->config; + clock_mchp_data_t *data = dev->data; + int inst = gclkgen_init->subsys.bits.inst; + + uint32_t val32; + + /* Check if gclkgen clock is already on */ + if ((data->fdpll_src_on_status & (1 << inst)) != 0) { + /* Early error handling return for code readability and maintainability */ + return; + } + + /* Check if source of gclk generator is off */ + if ((data->gclkgen_src_on_status & (1 << gclkgen_init->src)) == 0) { + /* Early error handling return for code readability and maintainability */ + return; + } + + if (inst <= GCLK_IO_MAX) { + data->gclkpin_freq[inst] = gclkgen_init->pin_src_freq; + } + + /* GENCTRL */ + val32 = 0; + /* check range for div_factor, gclk1: 0 - 65535, others: 0 - 255 */ + if ((inst == 1) || (gclkgen_init->div_factor <= 0xFF)) { + val32 |= GCLK_GENCTRL_DIV(gclkgen_init->div_factor); + } + val32 |= ((gclkgen_init->run_in_standby_en != 0) ? GCLK_GENCTRL_RUNSTDBY(1) : 0); + if (gclkgen_init->div_select == 0) { /* div-factor */ + val32 |= GCLK_GENCTRL_DIVSEL(GCLK_GENCTRL_DIVSEL_DIV1_Val); + } else { /* div-factor-power */ + val32 |= GCLK_GENCTRL_DIVSEL(GCLK_GENCTRL_DIVSEL_DIV2_Val); + } + val32 |= ((gclkgen_init->pin_output_en != 0) ? GCLK_GENCTRL_OE(1) : 0); + val32 |= GCLK_GENCTRL_OOV(gclkgen_init->pin_output_off_val); + val32 |= ((gclkgen_init->improve_duty_cycle_en != 0) ? GCLK_GENCTRL_IDC(1) : 0); + val32 |= ((gclkgen_init->enable != 0) ? GCLK_GENCTRL_GENEN(1) : 0); + val32 |= GCLK_GENCTRL_SRC(gclkgen_init->src); + + config->gclk_regs->GCLK_GENCTRL[inst] = val32; + while (config->gclk_regs->GCLK_SYNCBUSY != 0) { + } + + /* To avoid changing osc48m, while gclk0 is driven by it. Else will affect CPU */ + if (inst == CLOCK_MCHP_GCLKGEN_GEN0) { + data->gclk0_src = gclkgen_init->src; + } + + data->fdpll_src_on_status |= (1 << inst); + if (inst == CLOCK_MCHP_GCLKGEN_GEN1) { + data->gclkgen_src_on_status |= (1 << CLOCK_MCHP_GCLK_SRC_GCLKGEN1); + } +} + +/** + * @brief initialize peripheral gclk from device tree node. + */ +void clock_gclkperiph_init(const struct device *dev, uint32_t subsys_val, uint8_t pch_src, + uint8_t enable) +{ + const clock_mchp_config_t *config = dev->config; + clock_mchp_subsys_t subsys; + uint32_t val32; + + subsys.val = subsys_val; + + /* PCHCTRL */ + val32 = 0; + val32 |= ((enable != 0) ? GCLK_PCHCTRL_CHEN(1) : 0); + val32 |= GCLK_PCHCTRL_GEN(pch_src); + + config->gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] = val32; +} + +/** + * @brief initialize cpu mclk from device tree node. + */ +void clock_mclkcpu_init(const struct device *dev, uint8_t cpu_div) +{ + const clock_mchp_config_t *config = dev->config; + + config->mclk_regs->MCLK_CPUDIV = MCLK_CPUDIV_CPUDIV(cpu_div); +} + +/** + * @brief initialize peripheral mclk from device tree node. + */ +void clock_mclkperiph_init(const struct device *dev, uint32_t subsys_val, uint8_t enable) +{ + const clock_mchp_config_t *config = dev->config; + clock_mchp_subsys_t subsys; + + uint32_t mask; + __IO uint32_t *mask_reg; + + subsys.val = subsys_val; + mask = 1 << subsys.bits.mclkmaskbit; + mask_reg = get_mclkbus_mask_reg(config->mclk_regs, subsys.bits.mclkbus); + + if (mask_reg != NULL) { + if (enable == true) { + *mask_reg |= mask; + + } else { + *mask_reg &= ~mask; + } + } +} + +#define CLOCK_MCHP_PROCESS_XOSC(node) \ + clock_xosc_init_t xosc_init = {0}; \ + xosc_init.startup_time = DT_ENUM_IDX(node, xosc_startup_time); \ + xosc_init.automatic_amplitude_gain_control_en = \ + DT_PROP(node, xosc_automatic_amplitude_gain_control_en); \ + xosc_init.on_demand_en = DT_PROP(node, xosc_on_demand_en); \ + xosc_init.run_in_standby_en = DT_PROP(node, xosc_run_in_standby_en); \ + xosc_init.clock_failure_detection_en = DT_PROP(node, xosc_clock_failure_detection_en); \ + xosc_init.xtal_en = DT_PROP(node, xosc_xtal_en); \ + xosc_init.enable = DT_PROP(node, xosc_en); \ + xosc_init.frequency = DT_PROP(node, xosc_frequency); \ + clock_xosc_init(dev, &xosc_init); + +#define CLOCK_MCHP_PROCESS_OSC48M(node) \ + clock_osc48m_init_t osc48m_init = {0}; \ + osc48m_init.on_demand_en = DT_PROP(node, osc48m_on_demand_en); \ + osc48m_init.run_in_standby_en = DT_PROP(node, osc48m_run_in_standby_en); \ + osc48m_init.enable = DT_PROP(node, osc48m_en); \ + osc48m_init.post_divider_freq = DT_ENUM_IDX(node, osc48m_post_divider_freq); \ + clock_osc48m_init(dev, &osc48m_init); + +#define CLOCK_MCHP_PROCESS_FDPLL(node) \ + clock_fdpll_init_t fdpll_init = {0}; \ + fdpll_init.on_demand_en = DT_PROP(node, fdpll_on_demand_en); \ + fdpll_init.run_in_standby_en = DT_PROP(node, fdpll_run_in_standby_en); \ + fdpll_init.enable = DT_PROP(node, fdpll_en); \ + fdpll_init.divider_ratio_frac = DT_PROP(node, fdpll_divider_ratio_frac); \ + fdpll_init.divider_ratio_int = DT_PROP(node, fdpll_divider_ratio_int); \ + fdpll_init.xosc_clock_divider = DT_PROP(node, fdpll_xosc_clock_divider); \ + fdpll_init.lock_bypass_en = DT_PROP(node, fdpll_lock_bypass_en); \ + fdpll_init.src = DT_ENUM_IDX(node, fdpll_src); \ + fdpll_init.wakeup_fast_en = DT_PROP(node, fdpll_wakeup_fast_en); \ + fdpll_init.low_power_en = DT_PROP(node, fdpll_low_power_en); \ + fdpll_init.pi_filter_type = DT_ENUM_IDX(node, fdpll_pi_filter_type); \ + fdpll_init.output_prescalar = DT_ENUM_IDX(node, fdpll_output_prescalar); \ + clock_fdpll_init(dev, &fdpll_init); + +#define CLOCK_MCHP_PROCESS_RTC(node) clock_rtc_init(dev, DT_ENUM_IDX(node, rtc_src)); + +#define CLOCK_MCHP_PROCESS_XOSC32K(node) \ + clock_xosc32k_init_t xosc32k_init = {0}; \ + xosc32k_init.startup_time = DT_ENUM_IDX(node, xosc32k_startup_time); \ + xosc32k_init.on_demand_en = DT_PROP(node, xosc32k_on_demand_en); \ + xosc32k_init.run_in_standby_en = DT_PROP(node, xosc32k_run_in_standby_en); \ + xosc32k_init.xosc32k_1khz_en = DT_PROP(node, xosc32k_1khz_en); \ + xosc32k_init.xosc32k_32khz_en = DT_PROP(node, xosc32k_32khz_en); \ + xosc32k_init.xtal_en = DT_PROP(node, xosc32k_xtal_en); \ + xosc32k_init.enable = DT_PROP(node, xosc32k_en); \ + xosc32k_init.cfd_en = DT_PROP(node, xosc32k_cfd_en); \ + clock_xosc32k_init(dev, &xosc32k_init); + +#define CLOCK_MCHP_PROCESS_OSC32K(node) \ + clock_osc32k_init_t osc32k_init = {0}; \ + osc32k_init.startup_time = DT_ENUM_IDX(node, osc32k_startup_time); \ + osc32k_init.on_demand_en = DT_PROP(node, osc32k_on_demand_en); \ + osc32k_init.run_in_standby_en = DT_PROP(node, osc32k_run_in_standby_en); \ + osc32k_init.osc32k_1khz_en = DT_PROP(node, osc32k_1khz_en); \ + osc32k_init.osc32k_32khz_en = DT_PROP(node, osc32k_32khz_en); \ + osc32k_init.enable = DT_PROP(node, osc32k_en); \ + clock_osc32k_init(dev, &osc32k_init); + +#define CLOCK_MCHP_ITERATE_GCLKGEN(child) \ + { \ + clock_gclkgen_init_t gclkgen_init = {0}; \ + gclkgen_init.subsys.val = DT_PROP(child, subsystem); \ + gclkgen_init.div_factor = DT_PROP(child, gclkgen_div_factor); \ + gclkgen_init.run_in_standby_en = DT_PROP(child, gclkgen_run_in_standby_en); \ + gclkgen_init.div_select = DT_ENUM_IDX(child, gclkgen_div_select); \ + gclkgen_init.pin_output_en = DT_PROP(child, gclkgen_pin_output_en); \ + gclkgen_init.pin_output_off_val = DT_ENUM_IDX(child, gclkgen_pin_output_off_val); \ + gclkgen_init.improve_duty_cycle_en = \ + DT_PROP(child, gclkgen_improve_duty_cycle_en); \ + gclkgen_init.enable = DT_PROP(child, gclkgen_en); \ + gclkgen_init.src = DT_ENUM_IDX(child, gclkgen_src); \ + gclkgen_init.pin_src_freq = DT_PROP(child, gclkgen_pin_src_freq); \ + clock_gclkgen_init(dev, &gclkgen_init); \ + } + +#define CLOCK_MCHP_ITERATE_GCLKPERIPH(child) \ + { \ + clock_gclkperiph_init(dev, DT_PROP(child, subsystem), \ + DT_ENUM_IDX(child, gclkperiph_src), \ + DT_PROP(child, gclkperiph_en)); \ + } + +#define CLOCK_MCHP_PROCESS_MCLKCPU(node) clock_mclkcpu_init(dev, DT_PROP(node, mclk_cpu_div)); + +#define CLOCK_MCHP_ITERATE_MCLKPERIPH(child) \ + { \ + clock_mclkperiph_init(dev, DT_PROP(child, subsystem), DT_PROP(child, mclk_en)); \ + } + +#endif /* CONFIG_CLOCK_CONTROL_MCHP_CONFIG_BOOTUP */ + +/** + * @brief clock driver initialization function. + */ +static int clock_mchp_init(const struct device *dev) +{ + uint32_t val32; + +#if CONFIG_CLOCK_CONTROL_MCHP_CONFIG_BOOTUP + const clock_mchp_config_t *config = dev->config; + clock_mchp_data_t *data = dev->data; + + /* Program flash wait states, before configuring clock frequencies */ + val32 = NVMCTRL_REGS->NVMCTRL_CTRLB; + val32 &= ~NVMCTRL_CTRLB_RWS_Msk; + val32 |= NVMCTRL_CTRLB_RWS(config->flash_wait_states); + NVMCTRL_REGS->NVMCTRL_CTRLB = val32; + + /* iteration-1 */ + CLOCK_MCHP_PROCESS_OSC48M(DT_NODELABEL(osc48m)); + CLOCK_MCHP_PROCESS_XOSC(DT_NODELABEL(xosc)); + CLOCK_MCHP_PROCESS_XOSC32K(DT_NODELABEL(xosc32k)); + CLOCK_MCHP_PROCESS_OSC32K(DT_NODELABEL(osc32k)); + + config->gclk_regs->GCLK_CTRLA = GCLK_CTRLA_SWRST(1); + while (config->gclk_regs->GCLK_SYNCBUSY != 0) { + } + + /* To avoid changing osc48m, while gclk0 is driven by it. Else will affect CPU */ + data->gclk0_src = CLOCK_MCHP_GCLK_SRC_OSC48M; + + for (int i = 0; i < CLOCK_INIT_ITERATION_COUNT; i++) { + DT_FOREACH_CHILD(DT_NODELABEL(gclkgen), CLOCK_MCHP_ITERATE_GCLKGEN); + CLOCK_MCHP_PROCESS_FDPLL(DT_NODELABEL(fdpll)); + } + + CLOCK_MCHP_PROCESS_RTC(DT_NODELABEL(rtcclock)); + DT_FOREACH_CHILD(DT_NODELABEL(gclkperiph), CLOCK_MCHP_ITERATE_GCLKPERIPH); + DT_FOREACH_CHILD(DT_NODELABEL(mclkperiph), CLOCK_MCHP_ITERATE_MCLKPERIPH); + + CLOCK_MCHP_PROCESS_MCLKCPU(DT_NODELABEL(mclkcpu)); +#endif /* CONFIG_CLOCK_CONTROL_MCHP_CONFIG_BOOTUP */ + + /* Return CLOCK_SUCCESS indicating successful initialization. */ + return CLOCK_SUCCESS; +} + +/****************************************************************************** + * @brief Zephyr driver instance creation + *****************************************************************************/ +static DEVICE_API(clock_control, clock_mchp_driver_api) = { + .on = clock_mchp_on, + .off = clock_mchp_off, + .get_status = clock_mchp_get_status, + +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE + .get_rate = clock_mchp_get_rate, +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ + +#if CONFIG_CLOCK_CONTROL_MCHP_CONFIG_RUNTIME + .configure = clock_mchp_configure, +#endif /* CONFIG_CLOCK_CONTROL_MCHP_CONFIG_RUNTIME */ +}; + +#define CLOCK_MCHP_CONFIG_DEFN() \ + static const clock_mchp_config_t clock_mchp_config = { \ + .on_timeout_ms = DT_PROP_OR(CLOCK_NODE, on_timeout_ms, 5), \ + .flash_wait_states = DT_PROP_OR(CLOCK_NODE, flash_wait_states, 3), \ + .mclk_regs = (mclk_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, mclk), \ + .oscctrl_regs = (oscctrl_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, oscctrl), \ + .osc32kctrl_regs = \ + (osc32kctrl_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, osc32kctrl), \ + .gclk_regs = (gclk_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, gclk)} + +#define CLOCK_MCHP_DATA_DEFN() static clock_mchp_data_t clock_mchp_data; + +#define CLOCK_MCHP_DEVICE_INIT(n) \ + CLOCK_MCHP_CONFIG_DEFN(); \ + CLOCK_MCHP_DATA_DEFN(); \ + DEVICE_DT_INST_DEFINE(n, clock_mchp_init, NULL, &clock_mchp_data, &clock_mchp_config, \ + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &clock_mchp_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(CLOCK_MCHP_DEVICE_INIT) diff --git a/dts/arm/microchip/pic32c/pic32cm_jh/common/pic32cm_jh.dtsi b/dts/arm/microchip/pic32c/pic32cm_jh/common/pic32cm_jh.dtsi index c8ee3bb854398..422d3700fc4b9 100644 --- a/dts/arm/microchip/pic32c/pic32cm_jh/common/pic32cm_jh.dtsi +++ b/dts/arm/microchip/pic32c/pic32cm_jh/common/pic32cm_jh.dtsi @@ -8,6 +8,7 @@ #include #include +#include / { cpus { @@ -38,6 +39,59 @@ compatible = "mmio-sram"; }; + clock: clock@40000800 { + compatible = "microchip,pic32cm-jh-clock"; + reg = <0x40000800 0x24>, <0x40001000 0x58>, + <0x40001400 0x20>, <0x40001c00 0x140>; + reg-names = "mclk", "oscctrl", + "osc32kctrl", "gclk"; + + xosc: xosc { + compatible = "microchip,pic32cm-jh-xosc"; + }; + + osc48m: osc48m { + compatible = "microchip,pic32cm-jh-osc48m"; + }; + + fdpll: fdpll { + compatible = "microchip,pic32cm-jh-fdpll"; + }; + + rtcclock: rtcclock { + compatible = "microchip,pic32cm-jh-rtc"; + #clock-cells = <1>; + }; + + xosc32k: xosc32k { + compatible = "microchip,pic32cm-jh-xosc32k"; + }; + + osc32k: osc32k { + compatible = "microchip,pic32cm-jh-osc32k"; + }; + + gclkgen: gclkgen { + compatible = "microchip,pic32cm-jh-gclkgen"; + + }; + + gclkperiph: gclkperiph { + compatible = "microchip,pic32cm-jh-gclkperiph"; + #clock-cells = <1>; + }; + + mclkcpu: mclkcpu { + compatible = "microchip,pic32cm-jh-mclkcpu"; + mclk-cpu-div = <1>; + }; + + mclkperiph: mclkperiph { + compatible = "microchip,pic32cm-jh-mclkperiph"; + #clock-cells = <1>; + }; + }; + pinctrl: pinctrl@41000000 { compatible = "microchip,port-g1-pinctrl"; #address-cells = <1>; diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-clock.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-clock.yaml new file mode 100644 index 0000000000000..1b4074018021d --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-clock.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip PIC32CM_JH SOC family clock + +description: | + Microchip PIC32CM_JH SOC family clock (OSCCTRL, OSC32KCTRL, GCLK, MCLK) + +include: + - name: base.yaml + - name: pinctrl-device.yaml + +compatible: "microchip,pic32cm-jh-clock" + +properties: + on-timeout-ms: + type: int + default: 5 + description: | + Timeout in milliseconds for clock to be on. + + Driver waits in clock on API to check if the clock is actually on, + so that the waiting time is not indefinite. + + flash-wait-states: + type: int + default: 0 + description: | + Number of wait states for a flash read operation. + + Change this value based on the NVM access time and system frequency + up to 15 wait states. diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-fdpll.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-fdpll.yaml new file mode 100644 index 0000000000000..b9f1483498079 --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-fdpll.yaml @@ -0,0 +1,133 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH FDPLL clock + +description: | + Digital Phase Locked Loop (FDPLL), 48 MHz to 96 MHz output frequency from a 32 kHz to 2 MHz + reference clock. + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-fdpll" + +properties: + fdpll-on-demand-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: The oscillator is always on + 1: The oscillator is running when a peripheral is requesting the oscillator to be used as a + clock source. The oscillator is not running if no peripheral is requesting the clock source. + Important: Initializing it with 1, along with clock enabled, can lead to indefinite wait + for the clock to be on, if there is no peripheral request for the clock in the sequence of + clock Initialization. If required, better to turn on the clock using API, instead of + enabling both during startup. + + fdpll-run-in-standby-en: + type: int + enum: + - 0 + - 1 + default: 1 + description: | + 0: The DPLLn is not running in standby sleep mode if no peripheral requests the clock. + 1: The DPLLn is running in standby sleep mode. + If ONDEMAND is one, the DPLLn will be running when a peripheral is requesting the clock. If + ONDEMAND is false, the clock source will always be running in standby sleep mode. + + fdpll-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Oscillator Enable + + fdpll-divider-ratio-frac: + type: int + default: 0 + description: | + Set the fractional part of the frequency multiplier. (0 - 31) + + fdpll-divider-ratio-int: + type: int + default: 0 + description: | + Set the integer part of the frequency multiplier. (0 - 4095) + + fdpll-xosc-clock-divider: + type: int + default: 0 + description: | + Set the XOSC clock division factor (0 - 2047) + + fdpll-lock-bypass-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Lock Bypass + + fdpll-src: + type: string + enum: + - "gclk0" + - "gclk1" + - "gclk2" + - "gclk3" + - "gclk4" + - "gclk5" + - "gclk6" + - "gclk7" + - "gclk8" + - "xosc32k" + - "xosc" + default: "xosc32k" + description: | + Reference source clock selection + + fdpll-wakeup-fast-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Wake Up Fast + + fdpll-low-power-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + When enabled, Time to Digital Converter is disabled (increase the output jitter). + + fdpll-pi-filter-type: + type: string + enum: + - "default" + - "low-bandwidth" + - "high-bandwidth" + - "high-damping" + default: "default" + description: | + Proportional Integral Filter Selection + + fdpll-output-prescalar: + type: string + enum: + - "div1" + - "div2" + - "div4" + default: "div1" + description: | + Output prescalar divider. diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-gclkgen.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-gclkgen.yaml new file mode 100644 index 0000000000000..f653a1ac133bd --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-gclkgen.yaml @@ -0,0 +1,108 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH Generic clock generator + +description: | + The Generic Clock controller (GCLK) features 9 Generic Clock Generators 0..8 that can + provide a wide range of clock frequencies. + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-gclkgen" + +child-binding: + properties: + subsystem: + type: int + required: true + description: | + Clock subsystem + + gclkgen-div-factor: + type: int + default: 0 + description: | + Represent a division value for the corresponding Generator. The actual division factor is + dependent on the state of div-select (gclk1 0 - 65535, others 0 - 255) + + gclkgen-run-in-standby-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Keep the Generator running in Standby as long as it is configured to output to a dedicated + GCLK_IOn pin. If output is not configured to a pin, this field has no effect and the + generator will only be running if a peripheral requires the clock. + + gclkgen-div-select: + type: string + enum: + - "div-factor" + - "div-factor-power" + default: "div-factor" + description: | + The Generator clock frequency equals the clock source frequency divided by div-factor + DIV_FACTOR_POWER: The Generator clock frequency equals the clock source frequency divided + by 2^(N+1), where N is the div-factor + + gclkgen-pin-output-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Generator clock output to the corresponding pin, if that pin is not configured as input + source. + + gclkgen-pin-output-off-val: + type: string + enum: + - "low" + - "high" + default: "low" + description: | + Output value of the corresponding pin, when the Generator is turned off or the output-en is + false, as long as the pin is not source. + + gclkgen-improve-duty-cycle-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Improve the duty cycle of the Generator output to 50/50 for odd division factors + + gclkgen-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Enable gclk generator + + gclkgen-src: + type: string + enum: + - "xosc" + - "gclk-pin" + - "gclk1" + - "osculp32k" + - "osc32k" + - "xosc32k" + - "osc48m" + - "fdpll" + default: "xosc" + description: | + Generator source clock selection + + gclkgen-pin-src-freq: + type: int + default: 0 + description: | + External input clock frequency of the pin, when used as source. (0 - 200000000) diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-gclkperiph.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-gclkperiph.yaml new file mode 100644 index 0000000000000..33f012b79aaa7 --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-gclkperiph.yaml @@ -0,0 +1,60 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH Generic clock peripheral + +description: | + Peripheral channel gclk clock configuration. The outputs from the Generators are used as sources + for the Peripheral Channels, which provide the Generic Clock (GCLK_PERIPH) to the peripheral + modules. + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-gclkperiph" + +properties: + "#clock-cells": + const: 1 + type: int + description: | + The subsystem cell is to identify a clock controller sub-system. + + The subsystem can be referred from include\zephyr\dt-bindings\clock\mchp_pic32cm_jh_clock.h, + under the GCLKPERIPH_TYPE section of ids. + All clock control API use this value to specify the clock on which the API operates. + Since subsystem is opaque to the user, it can be accessed from the devicetree node and used. + +clock-cells: + - subsystem + +child-binding: + properties: + subsystem: + type: int + required: true + description: Clock subsystem + + gclkperiph-src: + type: string + enum: + - "gclk0" + - "gclk1" + - "gclk2" + - "gclk3" + - "gclk4" + - "gclk5" + - "gclk6" + - "gclk7" + - "gclk8" + default: "gclk0" + description: | + Generator to be used as the source of a peripheral clock + + gclkperiph-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Enable a peripheral channel diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-mclkcpu.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-mclkcpu.yaml new file mode 100644 index 0000000000000..ef6c626aec7e0 --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-mclkcpu.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH Main clock for CPU + +description: | + Main Clock Controller provides synchronous system clocks to the CPU. + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-mclkcpu" + +properties: + mclk-cpu-div: + type: int + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + - 32 + - 64 + - 128 + default: 1 + description: | + CPU Clock Division Factor diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-mclkperiph.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-mclkperiph.yaml new file mode 100644 index 0000000000000..70d8926d9c405 --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-mclkperiph.yaml @@ -0,0 +1,41 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH MCLK (Main Clock) peripheral + +description: | + Main Clock Controller provides synchronous system clocks to the modules + connected to the AHBx and the APBx buses. + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-mclkperiph" + +properties: + "#clock-cells": + const: 1 + type: int + description: | + The subsystem cell is to identify a clock controller sub-system. + + The subsystem can be referred from include\zephyr\dt-bindings\clock\mchp_pic32cm_jh_clock.h, + under the MCLKPERIPH_TYPE section of ids. + All clock control API use this value to specify the clock on which the API operates. + Since subsystem is opaque to the user, it can be accessed from the devicetree node and used. + +clock-cells: + - subsystem + +child-binding: + properties: + subsystem: + type: int + required: true + description: Clock subsystem + mclk-en: + type: int + enum: + - 0 + - 1 + required: true + description: Enable mclk to the peripheral diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-osc32k.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-osc32k.yaml new file mode 100644 index 0000000000000..0321a48624b76 --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-osc32k.yaml @@ -0,0 +1,79 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH Internal Oscillator (OSC32K) Control + +description: | + 32.768 kHz High Accuracy Internal Oscillator (OSC32K). + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-osc32k" + +properties: + osc32k-startup-time: + type: string + enum: + - "183-us" + - "214-us" + - "275-us" + - "397-us" + - "641-us" + - "1129-us" + - "2106-us" + - "4059-us" + default: "183-us" + description: | + Oscillator Start-Up Time + + osc32k-on-demand-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: The oscillator is always on, if standby-en is true, else run in + Standby Sleep mode if requested by a peripheral. + 1: Run if requested by peripheral + Important: Initializing it with 1, along with clock enabled, can lead to indefinite wait for + the clock to be on, if there is no peripheral request for the clock in the sequence of clock + Initialization. If required, better to turn on the clock using API, instead of enabling both + during startup. + + osc32k-run-in-standby-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: Run if requested by peripheral + 1: The oscillator is always on, if demand-en is false + + osc32k-1khz-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 1kHz Output Enable + + osc32k-32khz-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 32kHz output is enable + + osc32k-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Oscillator Enable diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-osc48m.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-osc48m.yaml new file mode 100644 index 0000000000000..7f128643a147a --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-osc48m.yaml @@ -0,0 +1,71 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH Internal Oscillator (OSC48M) + +description: | + 48MHz Internal Oscillator (OSC48M). + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-osc48m" + +properties: + osc48m-on-demand-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: The oscillator is always on + 1: The oscillator is running when a peripheral is requesting the oscillator to be used as a + clock source. The oscillator is not running if no peripheral is requesting the clock source. + Important: Initializing it with 1, along with clock enabled, can lead to indefinite wait for + the clock to be on, if there is no peripheral request for the clock in the sequence of clock + Initialization. If required, better to turn on the clock using API, instead of enabling both + during startup. + + osc48m-run-in-standby-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: The OSC48M is not running in standby sleep mode if no peripheral requests the clock. + 1: The OSC48M is running in standby sleep mode. + If ONDEMAND is one, the OSC48M will be running when a peripheral is requesting the clock. If + ONDEMAND is false, the clock source will always be running in standby sleep mode. + + osc48m-en: + type: int + enum: + - 0 + - 1 + default: 1 + description: | + Oscillator Enable + + osc48m-post-divider-freq: + type: string + enum: + - "48-mhz" + - "24-mhz" + - "16-mhz" + - "12-mhz" + - "9.6-mhz" + - "8-mhz" + - "6.86-mhz" + - "6-mhz" + - "5.33-mhz" + - "4.8-mhz" + - "4.36-mhz" + - "4-mhz" + - "3.69-mhz" + - "3.43-mhz" + - "3.2-mhz" + - "3-mhz" + default: "4-mhz" + description: | + Control the oscillator frequency range by adjusting the division ratio. diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-rtc.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-rtc.yaml new file mode 100644 index 0000000000000..ef81aa870e43b --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-rtc.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH RTC clock + +description: | + RTC clock configuration. + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-rtc" + +properties: + "#clock-cells": + const: 1 + type: int + + rtc-src: + type: string + enum: + - "ULP1K" + - "ULP32K" + - "OSC1K" + - "OSC32K" + - "XOSC1K" + - "XOSC32K" + default: "ULP1K" + description: | + RTC source clock selection + +clock-cells: + - subsystem diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-xosc.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-xosc.yaml new file mode 100644 index 0000000000000..54f3c99075d35 --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-xosc.yaml @@ -0,0 +1,109 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH Crystal Oscillator (XOSC) + +description: | + 0.4-32 MHz Crystal Oscillator (XOSC). + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-xosc" + +properties: + xosc-startup-time: + type: int + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + - 32 + - 64 + - 128 + - 256 + - 512 + - 1024 + - 2048 + - 4096 + - 8192 + - 16384 + - 32768 + default: 1 + description: | + XOSC start-up time. Select number of OSCULP32K oscillator clock cycles. + + xosc-automatic-amplitude-gain-control-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Amplitude gain will be automatically adjusted during Crystal Oscillator operation + + xosc-on-demand-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: The oscillator is always ON normally. + In standby sleep mode, oscillator will be OFF if there is no peripheral request, + unless run-in-standby-en is 1. + 1: In both normal and standby sleep mode, The oscillator is ON, + when a peripheral is requesting the oscillator to be used as a clock source. + The oscillator is OFF if no peripheral is requesting the clock source. + Important: Initializing it with 1, along with clock enabled, can lead to indefinite wait + for the clock to be on, if there is no peripheral request for the clock in the sequence of + clock Initialization. If required, better to turn on the clock using API, instead of + enabling both during startup. + + xosc-run-in-standby-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: The XOSCn is OFF in standby sleep mode if no peripheral requests the clock. + 1: The XOSCn is always ON in standby sleep mode, unless on-demand-en is 1. + If on-demand-en is 1, the XOSCn will be ON only when a peripheral is requesting + the clock, even if run-in-standby-en is 1. + + xosc-clock-failure-detection-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Clock Failure Detector Enable + + xosc-xtal-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Selects external clock or crystal oscillator + 0 - External clock connected on XIN. XOUT can be used as general-purpose I/O. + 1 - Crystal connected to XIN/XOUT. + + xosc-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Oscillator Enable + + xosc-frequency: + type: int + default: 12000000 + description: | + Crystal/External clock frequency for XOSC Controller diff --git a/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-xosc32k.yaml b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-xosc32k.yaml new file mode 100644 index 0000000000000..614f0a7347935 --- /dev/null +++ b/dts/bindings/clock/microchip/pic32cm_jh/microchip,pic32cm-jh-xosc32k.yaml @@ -0,0 +1,99 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: PIC32CM_JH External Crystal Oscillator (XOSC32K) + +description: | + 32.768 kHz External Crystal Oscillator (XOSC32K) Control. + +include: [base.yaml] + +compatible: "microchip,pic32cm-jh-xosc32k" + +properties: + xosc32k-startup-time: + type: string + enum: + - "122-us" + - "1.06-ms" + - "62.6-ms" + - "125-ms" + - "500-ms" + - "1-s" + - "2-s" + - "4-s" + default: "122-us" + description: | + Oscillator Start-Up Time + + xosc32k-on-demand-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: The oscillator is always on, if standby-en is true, else run in + Standby Sleep mode if requested by a peripheral. + 1: Run if requested by peripheral + Important: Initializing it with 1, along with clock enabled, can lead to indefinite wait for + the clock to be on, if there is no peripheral request for the clock in the sequence of clock + Initialization. If required, better to turn on the clock using API, instead of enabling both + during startup. + + xosc32k-run-in-standby-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 0: Run if requested by peripheral + 1: The oscillator is always on, if demand-en is false + + xosc32k-1khz-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 1kHz Output Enable + + xosc32k-32khz-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + 32kHz output is enable + + xosc32k-xtal-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Selects external clock or crystal oscillator + 0 - External clock connected on XIN. XOUT can be used as general-purpose I/O. + 1 - Crystal connected to XIN/XOUT. + + xosc32k-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Oscillator Enable + + xosc32k-cfd-en: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + Clock Failure Detector Enable diff --git a/include/zephyr/drivers/clock_control/mchp_clock_control.h b/include/zephyr/drivers/clock_control/mchp_clock_control.h index 6f4b52efd6792..906a72b1a7957 100644 --- a/include/zephyr/drivers/clock_control/mchp_clock_control.h +++ b/include/zephyr/drivers/clock_control/mchp_clock_control.h @@ -22,4 +22,8 @@ #include #endif /* CLOCK_CONTROL_MCHP_SAM_D5X_E5X */ +#if CONFIG_CLOCK_CONTROL_MCHP_PIC32CM_JH +#include +#endif /* CONFIG_CLOCK_CONTROL_MCHP_PIC32CM_JH */ + #endif /* INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_CONTROL_H_ */ diff --git a/include/zephyr/drivers/clock_control/mchp_clock_pic32cm_jh.h b/include/zephyr/drivers/clock_control/mchp_clock_pic32cm_jh.h new file mode 100644 index 0000000000000..c3c7df22a73d8 --- /dev/null +++ b/include/zephyr/drivers/clock_control/mchp_clock_pic32cm_jh.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file mchp_clock_pic32cm_jh.h + * @brief Clock control header file for Microchip pic32cm_jh family. + * + * This file provides clock driver interface definitions and structures + * for pic32cm_jh family + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_PIC32CM_JH_H_ +#define INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_PIC32CM_JH_H_ + +#include + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; +} clock_mchp_subsys_xosc_config_t; + +/** @brief Control the oscillator frequency range by adjusting the division ratio */ +typedef enum { + CLOCK_MCHP_DIVIDER_48_MHZ, + CLOCK_MCHP_DIVIDER_24_MHZ, + CLOCK_MCHP_DIVIDER_16_MHZ, + CLOCK_MCHP_DIVIDER_12_MHZ, + CLOCK_MCHP_DIVIDER_9_6_MHZ, + CLOCK_MCHP_DIVIDER_8_MHZ, + CLOCK_MCHP_DIVIDER_6_86_MHZ, + CLOCK_MCHP_DIVIDER_6_MHZ, + CLOCK_MCHP_DIVIDER_5_33_MHZ, + CLOCK_MCHP_DIVIDER_4_8_MHZ, + CLOCK_MCHP_DIVIDER_4_36_MHZ, + CLOCK_MCHP_DIVIDER_4_MHZ, + CLOCK_MCHP_DIVIDER_3_69_MHZ, + CLOCK_MCHP_DIVIDER_3_43_MHZ, + CLOCK_MCHP_DIVIDER_3_2_MHZ, + CLOCK_MCHP_DIVIDER_3_MHZ +} clock_mchp_osc48m_divider_freq_t; + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; + + /** @brief Control the oscillator frequency range by adjusting the division ratio */ + clock_mchp_osc48m_divider_freq_t post_divider_freq; +} clock_mchp_subsys_osc48m_config_t; + +/** @brief FDPLL source clocks */ +typedef enum { + CLOCK_MCHP_FDPLL_SRC_GCLK0, + CLOCK_MCHP_FDPLL_SRC_GCLK1, + CLOCK_MCHP_FDPLL_SRC_GCLK2, + CLOCK_MCHP_FDPLL_SRC_GCLK3, + CLOCK_MCHP_FDPLL_SRC_GCLK4, + CLOCK_MCHP_FDPLL_SRC_GCLK5, + CLOCK_MCHP_FDPLL_SRC_GCLK6, + CLOCK_MCHP_FDPLL_SRC_GCLK7, + CLOCK_MCHP_FDPLL_SRC_GCLK8, + CLOCK_MCHP_FDPLL_SRC_XOSC32K, + CLOCK_MCHP_FDPLL_SRC_XOSC, + + CLOCK_MCHP_FDPLL_SRC_MAX = CLOCK_MCHP_FDPLL_SRC_XOSC +} clock_mchp_fdpll_src_clock_t; + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; + + /** @brief Set the fractional part of the frequency multiplier. (0 - 31) */ + uint32_t divider_ratio_frac; + + /** @brief Set the integer part of the frequency multiplier. (0 - 4095) */ + uint32_t divider_ratio_int; + + /** @brief Set the XOSC clock division factor (0 - 2047) */ + uint32_t xosc_clock_divider; + + /** @brief Reference source clock selection */ + clock_mchp_fdpll_src_clock_t src; +} clock_mchp_subsys_fdpll_config_t; + +/** @brief RTC source clocks */ +typedef enum { + CLOCK_MCHP_RTC_SRC_ULP1K = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K, + CLOCK_MCHP_RTC_SRC_ULP32K = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K, + CLOCK_MCHP_RTC_SRC_OSC1K = OSC32KCTRL_RTCCTRL_RTCSEL_OSC1K, + CLOCK_MCHP_RTC_SRC_OSC32K = OSC32KCTRL_RTCCTRL_RTCSEL_OSC32K, + CLOCK_MCHP_RTC_SRC_XOSC1K = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K, + CLOCK_MCHP_RTC_SRC_XOSC32K = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K +} clock_mchp_rtc_src_clock_t; + +typedef struct { + /** @brief RTC source clock selection */ + clock_mchp_rtc_src_clock_t src; +} clock_mchp_subsys_rtc_config_t; + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; +} clock_mchp_subsys_xosc32k_config_t; + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; +} clock_mchp_subsys_osc32k_config_t; + +/** @brief Gclk Generator source clocks */ +typedef enum { + CLOCK_MCHP_GCLK_SRC_XOSC, + CLOCK_MCHP_GCLK_SRC_GCLKPIN, + CLOCK_MCHP_GCLK_SRC_GCLKGEN1, + CLOCK_MCHP_GCLK_SRC_OSCULP32K, + CLOCK_MCHP_GCLK_SRC_OSC32K, + CLOCK_MCHP_GCLK_SRC_XOSC32K, + CLOCK_MCHP_GCLK_SRC_OSC48M, + CLOCK_MCHP_GCLK_SRC_FDPLL, + + CLOCK_MCHP_GCLK_SRC_MAX = CLOCK_MCHP_GCLK_SRC_FDPLL +} clock_mchp_gclk_src_clock_t; + +typedef struct { + /** @brief Represent a division value for the corresponding Generator. The actual division + * factor is dependent on the state of div_select (gclk1 0 - 65535, others 0 - 255) + */ + uint16_t div_factor; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; + + /** @brief Generator source clock selection */ + clock_mchp_gclk_src_clock_t src; +} clock_mchp_subsys_gclkgen_config_t; + +/** @brief GCLK generator numbers */ +typedef enum { + CLOCK_MCHP_GCLKGEN_GEN0, + CLOCK_MCHP_GCLKGEN_GEN1, + CLOCK_MCHP_GCLKGEN_GEN2, + CLOCK_MCHP_GCLKGEN_GEN3, + CLOCK_MCHP_GCLKGEN_GEN4, + CLOCK_MCHP_GCLKGEN_GEN5, + CLOCK_MCHP_GCLKGEN_GEN6, + CLOCK_MCHP_GCLKGEN_GEN7, + CLOCK_MCHP_GCLKGEN_GEN8 +} clock_mchp_gclkgen_t; + +typedef struct { + /** @brief gclk generator source of a peripheral clock */ + clock_mchp_gclkgen_t src; +} clock_mchp_subsys_gclkperiph_config_t; + +/** @brief division ratio of mclk prescaler for CPU */ +typedef enum { + CLOCK_MCHP_MCLK_CPU_DIV_1 = 1, + CLOCK_MCHP_MCLK_CPU_DIV_2 = 2, + CLOCK_MCHP_MCLK_CPU_DIV_4 = 4, + CLOCK_MCHP_MCLK_CPU_DIV_8 = 8, + CLOCK_MCHP_MCLK_CPU_DIV_16 = 16, + CLOCK_MCHP_MCLK_CPU_DIV_32 = 32, + CLOCK_MCHP_MCLK_CPU_DIV_64 = 64, + CLOCK_MCHP_MCLK_CPU_DIV_128 = 128 +} clock_mchp_mclk_cpu_div_t; + +/** @brief MCLK configuration structure + * + * Used for CLOCK_MCHP_SUBSYS_TYPE_MCLKCPU + */ +typedef struct { + /** @brief division ratio of mclk prescaler for CPU */ + clock_mchp_mclk_cpu_div_t division_factor; +} clock_mchp_subsys_mclkcpu_config_t; + +/** @brief clock rate datatype + * + * Used for setting a clock rate + */ +typedef uint32_t *clock_mchp_rate_t; + +#endif /* INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_PIC32CM_JH_H_ */ diff --git a/include/zephyr/dt-bindings/clock/mchp_pic32cm_jh_clock.h b/include/zephyr/dt-bindings/clock/mchp_pic32cm_jh_clock.h new file mode 100644 index 0000000000000..ad41d321992b3 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/mchp_pic32cm_jh_clock.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file mchp_pic32cm_jh_clock.h + * @brief List clock subsystem IDs for pic32cm_jh family. + * + * Clock subsystem IDs. To be used in devicetree nodes, and as argument for clock API. + */ + +#ifndef INCLUDE_ZEPHYR_DT_BINDINGS_CLOCK_MCHP_PIC32CM_JH_CLOCK_H_ +#define INCLUDE_ZEPHYR_DT_BINDINGS_CLOCK_MCHP_PIC32CM_JH_CLOCK_H_ + +/** + * Encode clock type, mclk bus, mclk mask bit, gclk pch and instance number, + * to clock subsystem. + * + * - 00..07 (8 bits): inst + * + * - 08..13 (6 bits): gclkperiph + * (values from 0 to 47) + * + * - 14..19 (6 bits): mclkmaskbit + * (values from 0 to 31) + * + * - 20..25 (6 bits): mclkbus + * following values + * MBUS_AHB (0) + * MBUS_APBA (1) + * MBUS_APBB (2) + * MBUS_APBC (3) + * MBUS_APBD (4) + * + * - 26..31 (6 bits): type + * following values + * SUBSYS_TYPE_XOSC (0) + * SUBSYS_TYPE_OSC48M (1) + * SUBSYS_TYPE_FDPLL (2) + * SUBSYS_TYPE_RTC (3) + * SUBSYS_TYPE_XOSC32K (4) + * SUBSYS_TYPE_OSC32K (5) + * SUBSYS_TYPE_GCLKGEN (6) + * SUBSYS_TYPE_GCLKPERIPH (7) + * SUBSYS_TYPE_MCLKCPU (8) + * SUBSYS_TYPE_MCLKPERIPH (9) + * + * @param type clock subsystem type + * @param mclkbus select from the AHBx and the APBx buses + * @param mclkmaskbit select the module connected to AHBx or APBx bus (0 to 31) + * @param gclkperiph gclk peripheral channel number m in PCHTRLm (0 to 47) + * @param inst instance number of the specified clock type + */ +#define MCHP_CLOCK_DERIVE_ID(type, mclkbus, mclkmaskbit, gclkperiph, inst) \ + (((type) << 26) | ((mclkbus) << 20) | ((mclkmaskbit) << 14) | ((gclkperiph) << 8) | inst) + +/* XOSC_TYPE ids */ +#define CLOCK_MCHP_XOSC_ID MCHP_CLOCK_DERIVE_ID(0, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_XOSC_ID_MAX (0) + +/* OSC48M_TYPE ids */ +#define CLOCK_MCHP_OSC48M_ID MCHP_CLOCK_DERIVE_ID(1, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_OSC48M_ID_MAX (0) + +/* FDPLL_TYPE id */ +#define CLOCK_MCHP_FDPLL_ID MCHP_CLOCK_DERIVE_ID(2, 0x3f, 0x3f, 0, 0) +#define CLOCK_MCHP_FDPLL_ID_MAX (0) + +/* RTC_TYPE ids */ +#define CLOCK_MCHP_RTC_ID MCHP_CLOCK_DERIVE_ID(3, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_RTC_ID_MAX (0) + +/* XOSC32K_TYPE ids */ +#define CLOCK_MCHP_XOSC32K_ID_XOSC1K MCHP_CLOCK_DERIVE_ID(4, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_XOSC32K_ID_XOSC32K MCHP_CLOCK_DERIVE_ID(4, 0x3f, 0x3f, 0x3f, 1) +#define CLOCK_MCHP_XOSC32K_ID_MAX (1) + +/* OSC32K_TYPE ids */ +#define CLOCK_MCHP_OSC32K_ID_OSC1K MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_OSC32K_ID_OSC32K MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 1) +#define CLOCK_MCHP_OSC32K_ID_MAX (1) + +/* GCLKGEN_TYPE ids */ +#define CLOCK_MCHP_GCLKGEN_ID_GEN0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_GCLKGEN_ID_GEN1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 1) +#define CLOCK_MCHP_GCLKGEN_ID_GEN2 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 2) +#define CLOCK_MCHP_GCLKGEN_ID_GEN3 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 3) +#define CLOCK_MCHP_GCLKGEN_ID_GEN4 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 4) +#define CLOCK_MCHP_GCLKGEN_ID_GEN5 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 5) +#define CLOCK_MCHP_GCLKGEN_ID_GEN6 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 6) +#define CLOCK_MCHP_GCLKGEN_ID_GEN7 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 7) +#define CLOCK_MCHP_GCLKGEN_ID_GEN8 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 0x3f, 8) +#define CLOCK_MCHP_GCLKGEN_ID_MAX (8) + +/* GCLKPERIPH_TYPE ids */ +#define CLOCK_MCHP_GCLKPERIPH_ID_EIC MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 2, 0) +#define CLOCK_MCHP_GCLKPERIPH_ID_FREQM_MSR MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 3, 1) +#define CLOCK_MCHP_GCLKPERIPH_ID_FREQM_REF MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 4, 2) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_0 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 5, 3) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_1 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 6, 4) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_2 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 7, 5) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_3 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 8, 6) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_4 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 9, 7) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_5 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 10, 8) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_6 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 11, 9) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_7 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 12, 10) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_8 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 13, 11) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_9 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 14, 12) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_10 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 15, 13) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS_CHANNEL_11 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 16, 14) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM_0_7_SLOW MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 17, 15) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM0_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 18, 16) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM1_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 19, 17) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM2_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 20, 18) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM3_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 21, 19) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM4_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 22, 20) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM5_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 23, 21) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM6_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 24, 22) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM7_CORE MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 25, 23) +#define CLOCK_MCHP_GCLKPERIPH_ID_CAN0 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 26, 24) +#define CLOCK_MCHP_GCLKPERIPH_ID_CAN1 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 27, 25) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC0 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 28, 26) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC1 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 28, 27) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC2 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 29, 28) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC0 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 30, 29) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC1 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 30, 30) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC2 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 31, 31) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC3 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 31, 32) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC4 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 32, 33) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC5 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 33, 34) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC6 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 34, 35) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC7 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 35, 36) +#define CLOCK_MCHP_GCLKPERIPH_ID_ADC0 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 36, 37) +#define CLOCK_MCHP_GCLKPERIPH_ID_ADC1 MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 37, 38) +#define CLOCK_MCHP_GCLKPERIPH_ID_DAC MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 38, 39) +#define CLOCK_MCHP_GCLKPERIPH_ID_PTC MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 39, 40) +#define CLOCK_MCHP_GCLKPERIPH_ID_CCL MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 40, 41) +#define CLOCK_MCHP_GCLKPERIPH_ID_PDEC MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 41, 42) +#define CLOCK_MCHP_GCLKPERIPH_ID_AC MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 42, 43) +#define CLOCK_MCHP_GCLKPERIPH_ID_MAX (43) + +/* MCLKCPU_TYPE ids */ +#define CLOCK_MCHP_MCLKCPU_ID MCHP_CLOCK_DERIVE_ID(8, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_MCLKCPU_MAX (0) + +/* MCLKPERIPH_TYPE ids */ +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_APBA MCHP_CLOCK_DERIVE_ID(9, 0, 0, 0x3f, 0) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_APBB MCHP_CLOCK_DERIVE_ID(9, 0, 1, 0x3f, 1) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_APBC MCHP_CLOCK_DERIVE_ID(9, 0, 2, 0x3f, 2) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_DSU MCHP_CLOCK_DERIVE_ID(9, 0, 3, 0x3f, 3) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_HMATRIXHS MCHP_CLOCK_DERIVE_ID(9, 0, 4, 0x3f, 4) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_NVMCTRL MCHP_CLOCK_DERIVE_ID(9, 0, 5, 0x3f, 5) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_MCRAMC MCHP_CLOCK_DERIVE_ID(9, 0, 6, 0x3f, 6) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_DMAC MCHP_CLOCK_DERIVE_ID(9, 0, 7, 0x3f, 7) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_CAN0 MCHP_CLOCK_DERIVE_ID(9, 0, 8, 0x3f, 8) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_CAN1 MCHP_CLOCK_DERIVE_ID(9, 0, 9, 0x3f, 9) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_PAC MCHP_CLOCK_DERIVE_ID(9, 0, 10, 0x3f, 10) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_DIVAS MCHP_CLOCK_DERIVE_ID(9, 0, 12, 0x3f, 11) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_APBD MCHP_CLOCK_DERIVE_ID(9, 0, 13, 0x3f, 12) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_ICM MCHP_CLOCK_DERIVE_ID(9, 0, 14, 0x3f, 13) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_PAC MCHP_CLOCK_DERIVE_ID(9, 1, 0, 0x3f, 14) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_PM MCHP_CLOCK_DERIVE_ID(9, 1, 1, 0x3f, 15) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_MCLK MCHP_CLOCK_DERIVE_ID(9, 1, 2, 0x3f, 16) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_RSTC MCHP_CLOCK_DERIVE_ID(9, 1, 3, 0x3f, 17) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_OSCCTRL MCHP_CLOCK_DERIVE_ID(9, 1, 4, 0x3f, 18) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_OSC32KCTRL MCHP_CLOCK_DERIVE_ID(9, 1, 5, 0x3f, 19) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_SUPC MCHP_CLOCK_DERIVE_ID(9, 1, 6, 0x3f, 20) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_GCLK MCHP_CLOCK_DERIVE_ID(9, 1, 7, 0x3f, 21) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_WDT MCHP_CLOCK_DERIVE_ID(9, 1, 8, 0x3f, 22) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_RTC MCHP_CLOCK_DERIVE_ID(9, 1, 9, 0x3f, 23) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_EIC MCHP_CLOCK_DERIVE_ID(9, 1, 10, 0x3f, 24) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_FREQM MCHP_CLOCK_DERIVE_ID(9, 1, 11, 0x3f, 25) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_MCRAMC MCHP_CLOCK_DERIVE_ID(9, 1, 12, 0x3f, 26) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_PORT MCHP_CLOCK_DERIVE_ID(9, 2, 0, 0x3f, 27) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_DSU MCHP_CLOCK_DERIVE_ID(9, 2, 1, 0x3f, 28) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_NVMCTRL MCHP_CLOCK_DERIVE_ID(9, 2, 2, 0x3f, 29) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_HMATRIXHS MCHP_CLOCK_DERIVE_ID(9, 2, 5, 0x3f, 30) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_EVSYS MCHP_CLOCK_DERIVE_ID(9, 3, 0, 0x3f, 31) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_SERCOM0 MCHP_CLOCK_DERIVE_ID(9, 3, 1, 0x3f, 32) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_SERCOM1 MCHP_CLOCK_DERIVE_ID(9, 3, 2, 0x3f, 33) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_SERCOM2 MCHP_CLOCK_DERIVE_ID(9, 3, 3, 0x3f, 34) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_SERCOM3 MCHP_CLOCK_DERIVE_ID(9, 3, 4, 0x3f, 35) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_SERCOM4 MCHP_CLOCK_DERIVE_ID(9, 3, 5, 0x3f, 36) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_SERCOM5 MCHP_CLOCK_DERIVE_ID(9, 3, 6, 0x3f, 37) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC0 MCHP_CLOCK_DERIVE_ID(9, 3, 9, 0x3f, 38) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC1 MCHP_CLOCK_DERIVE_ID(9, 3, 10, 0x3f, 39) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC2 MCHP_CLOCK_DERIVE_ID(9, 3, 11, 0x3f, 40) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TC0 MCHP_CLOCK_DERIVE_ID(9, 3, 12, 0x3f, 41) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TC1 MCHP_CLOCK_DERIVE_ID(9, 3, 13, 0x3f, 42) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TC2 MCHP_CLOCK_DERIVE_ID(9, 3, 14, 0x3f, 43) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TC3 MCHP_CLOCK_DERIVE_ID(9, 3, 15, 0x3f, 44) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TC4 MCHP_CLOCK_DERIVE_ID(9, 3, 16, 0x3f, 45) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_ADC0 MCHP_CLOCK_DERIVE_ID(9, 3, 17, 0x3f, 46) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_ADC1 MCHP_CLOCK_DERIVE_ID(9, 3, 18, 0x3f, 47) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_AC MCHP_CLOCK_DERIVE_ID(9, 3, 19, 0x3f, 48) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_DAC MCHP_CLOCK_DERIVE_ID(9, 3, 20, 0x3f, 49) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_PTC MCHP_CLOCK_DERIVE_ID(9, 3, 21, 0x3f, 50) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_CCL MCHP_CLOCK_DERIVE_ID(9, 3, 22, 0x3f, 51) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_ICM MCHP_CLOCK_DERIVE_ID(9, 3, 25, 0x3f, 52) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_PDEC MCHP_CLOCK_DERIVE_ID(9, 3, 26, 0x3f, 53) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_SMBIST MCHP_CLOCK_DERIVE_ID(9, 3, 27, 0x3f, 54) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM6 MCHP_CLOCK_DERIVE_ID(9, 4, 0, 0x3f, 55) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM7 MCHP_CLOCK_DERIVE_ID(9, 4, 1, 0x3f, 56) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_TC5 MCHP_CLOCK_DERIVE_ID(9, 4, 2, 0x3f, 57) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_TC6 MCHP_CLOCK_DERIVE_ID(9, 4, 3, 0x3f, 58) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_TC7 MCHP_CLOCK_DERIVE_ID(9, 4, 4, 0x3f, 59) +#define CLOCK_MCHP_MCLKPERIPH_ID_MAX (59) + +#endif /* INCLUDE_ZEPHYR_DT_BINDINGS_CLOCK_MCHP_PIC32CM_JH_CLOCK_H_ */ diff --git a/soc/microchip/pic32c/pic32cm_jh/Kconfig b/soc/microchip/pic32c/pic32cm_jh/Kconfig index 5c70184088165..c9e3322e8cbab 100644 --- a/soc/microchip/pic32c/pic32cm_jh/Kconfig +++ b/soc/microchip/pic32c/pic32cm_jh/Kconfig @@ -9,3 +9,4 @@ config SOC_FAMILY_MICROCHIP_PIC32CM_JH select CPU_CORTEX_M_HAS_VTOR select CPU_HAS_ARM_MPU select SOC_RESET_HOOK + select CLOCK_CONTROL