From d788a9fcebb6b0828f1db9f94c28815bdfeff5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 27 Oct 2025 07:23:06 +0100 Subject: [PATCH 1/9] [nrf fromlist] drivers: counter: nrfx_rtc: Use GPPI instead of DPPI/PPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to use a (D)PPI manager - GPPI which covers all Nordic peripheral interconnect systems. Upstream PR #: 98327 Signed-off-by: Krzysztof Chruściński --- drivers/counter/Kconfig.nrfx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/counter/Kconfig.nrfx b/drivers/counter/Kconfig.nrfx index ed02411de261..e50b75063135 100644 --- a/drivers/counter/Kconfig.nrfx +++ b/drivers/counter/Kconfig.nrfx @@ -22,8 +22,7 @@ config COUNTER_RTC_WITH_PPI_WRAP $(dt_nodelabel_bool_prop,rtc1,ppi-wrap) || \ $(dt_nodelabel_bool_prop,rtc2,ppi-wrap) depends on COUNTER_NRF_RTC - select NRFX_PPI if HAS_HW_NRF_PPI - select NRFX_DPPI if HAS_HW_NRF_DPPIC + select NRFX_GPPI # Internal flag which detects if fixed top feature is enabled for any instance config COUNTER_RTC_CUSTOM_TOP_SUPPORT From 212115f815ba401b9146734be8c2058a40896a57 Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Fri, 14 Nov 2025 13:54:03 +0100 Subject: [PATCH 2/9] [nrf fromlist] drivers: clock_control: Separated nrf hfclk shim from nrf clock shim. Separated clock_control_nrf_hfclk shim from clock_control_nrf shim. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- .../nrf54l_10_15_cpuapp_common.dtsi | 4 + .../bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi | 4 + .../nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts | 4 + .../nrf54lm20bsim_nrf54lm20a_cpuapp.dts | 4 + .../nrf54l_05_10_15_cpuapp_common.dtsi | 4 + .../nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi | 4 + .../panb611evb_nrf54l15_cpuapp_common.dtsi | 4 + .../raytac_an54l15q_db_cpuapp_common.dtsi | 4 + .../ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts | 4 + drivers/clock_control/CMakeLists.txt | 4 + drivers/clock_control/Kconfig.nrf | 15 + drivers/clock_control/clock_control_nrf.c | 45 +- .../clock_control/clock_control_nrf_common.c | 41 ++ .../clock_control/clock_control_nrf_common.h | 20 + .../clock_control/clock_control_nrf_hfclk.c | 425 ++++++++++++++++++ .../clock_control_nrf_irq_handlers.ld | 2 + dts/arm/nordic/nrf51822.dtsi | 7 + dts/arm/nordic/nrf52805.dtsi | 7 + dts/arm/nordic/nrf52810.dtsi | 7 + dts/arm/nordic/nrf52811.dtsi | 7 + dts/arm/nordic/nrf52820.dtsi | 7 + dts/arm/nordic/nrf52832.dtsi | 7 + dts/arm/nordic/nrf52833.dtsi | 7 + dts/arm/nordic/nrf52840.dtsi | 7 + .../nordic/nrf5340_cpuapp_peripherals.dtsi | 7 + dts/arm/nordic/nrf5340_cpunet.dtsi | 7 + dts/arm/nordic/nrf91_peripherals.dtsi | 7 + .../clock/nordic,nrf-clock-hfclk.yaml | 15 + dts/bindings/clock/nordic,nrf-clock-xo.yaml | 15 + dts/vendor/nordic/nrf54l_05_10_15.dtsi | 7 + dts/vendor/nordic/nrf54lm20a.dtsi | 7 + .../clock_control_api/src/nrf_device_subsys.h | 20 + 32 files changed, 686 insertions(+), 43 deletions(-) create mode 100644 drivers/clock_control/clock_control_nrf_common.c create mode 100644 drivers/clock_control/clock_control_nrf_common.h create mode 100644 drivers/clock_control/clock_control_nrf_hfclk.c create mode 100644 drivers/clock_control/clock_control_nrf_irq_handlers.ld create mode 100644 dts/bindings/clock/nordic,nrf-clock-hfclk.yaml create mode 100644 dts/bindings/clock/nordic,nrf-clock-xo.yaml diff --git a/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi b/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi index 8671beb29cf6..3e2b19c68a1a 100644 --- a/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi +++ b/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi @@ -92,6 +92,10 @@ status = "okay"; }; +&xo { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi b/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi index e630abab4a9c..fd78f2d08998 100644 --- a/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi +++ b/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi @@ -92,6 +92,10 @@ status = "okay"; }; +&xo { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts index 35a052b78081..0640c6b2adc0 100644 --- a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts +++ b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts @@ -135,3 +135,7 @@ &clock { status = "okay"; }; + +&xo { + status = "okay"; +}; diff --git a/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts b/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts index bd424f2e15ec..e65262bae057 100644 --- a/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts +++ b/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts @@ -142,3 +142,7 @@ &clock { status = "okay"; }; + +&xo { + status = "okay"; +}; diff --git a/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi b/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi index f3c1d924d27c..dcae050111ac 100644 --- a/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi +++ b/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi @@ -101,6 +101,10 @@ status = "okay"; }; +&xo { + status = "okay"; +}; + &gpregret1 { status = "okay"; diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi index 0ee33f1fd45b..70ee2d89a05c 100644 --- a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi +++ b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi @@ -130,6 +130,10 @@ status = "okay"; }; +&xo { + status = "okay"; +}; + &ieee802154 { status = "okay"; }; diff --git a/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi b/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi index ba978a541286..a4e0b7add0fb 100644 --- a/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi +++ b/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi @@ -91,6 +91,10 @@ status = "okay"; }; +&xo { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi b/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi index 952a8f6d7aeb..bf42a5b3a1fa 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi +++ b/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi @@ -92,6 +92,10 @@ status = "okay"; }; +&xo { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts b/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts index 2380fcd5b8d3..ef7455d3a5df 100644 --- a/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts +++ b/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts @@ -99,6 +99,10 @@ status = "okay"; }; +&xo { + status = "okay"; +}; + &spi00 { status = "okay"; diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index f649af13c46e..975ec7bdcd52 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -60,6 +60,8 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HSFLL_LOCAL clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL clock_control_nrf_iron_hsfll_local.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK clock_control_nrf_hfclk.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_COMMON clock_control_nrf_common.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X clock_control_bl61x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL70X clock_control_bl70x.c) @@ -129,3 +131,5 @@ endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MAX32 clock_control_max32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_WCH_RCC clock_control_wch_rcc.c) + +zephyr_linker_sources(SECTIONS clock_control_nrf_irq_handlers.ld) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index a051ebd62b02..f8622eab5aba 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -323,6 +323,21 @@ config CLOCK_CONTROL_NRF_LFCLK_CLOCK_TIMEOUT_MS endif # CLOCK_CONTROL_NRF_LFCLK +config CLOCK_CONTROL_NRF_COMMON + bool + +config CLOCK_CONTROL_NRF_HFCLK + bool "NRF HFCLK driver support" + depends on DT_HAS_NORDIC_NRF_CLOCK_HFCLK_ENABLED + select CLOCK_CONTROL_NRF_COMMON + default y + +config CLOCK_CONTROL_NRF_XO + bool "NRF XO driver support" + depends on DT_HAS_NORDIC_NRF_CLOCK_XO_ENABLED + select CLOCK_CONTROL_NRF_COMMON + default y + config CLOCK_CONTROL_NRF_AUXPLL bool "nRF Auxiliary PLL driver" default y diff --git a/drivers/clock_control/clock_control_nrf.c b/drivers/clock_control/clock_control_nrf.c index f42a673b7597..977f7ab10949 100644 --- a/drivers/clock_control/clock_control_nrf.c +++ b/drivers/clock_control/clock_control_nrf.c @@ -10,6 +10,7 @@ #include #include #include "nrf_clock_calibration.h" +#include "clock_control_nrf_common.h" #include #include #include @@ -420,47 +421,6 @@ static void generic_hfclk_stop(void) irq_unlock(key); } - -void z_nrf_clock_bt_ctlr_hf_request(void) -{ - if (atomic_or(&hfclk_users, HF_USER_BT) & HF_USER_GENERIC) { - /* generic request already activated clock. */ - return; - } - - hfclk_start(); -} - -void z_nrf_clock_bt_ctlr_hf_release(void) -{ - /* It's not enough to use only atomic_and() here for synchronization, - * see the explanation in generic_hfclk_stop(). - */ - unsigned int key = irq_lock(); - - hfclk_users &= ~HF_USER_BT; - /* Skip stopping if generic is still requesting the clock. */ - if (!(hfclk_users & HF_USER_GENERIC)) { - struct nrf_clock_control_sub_data *sub_data = - get_sub_data(CLOCK_DEVICE, CLOCK_CONTROL_NRF_TYPE_HFCLK); - - /* State needs to be set to OFF as BT API does not call stop API which - * normally setting this state. - */ - sub_data->flags = CLOCK_CONTROL_STATUS_OFF; - hfclk_stop(); - } - - irq_unlock(key); -} - -#if DT_NODE_EXISTS(DT_NODELABEL(hfxo)) -uint32_t z_nrf_clock_bt_ctlr_hf_get_startup_time_us(void) -{ - return DT_PROP(DT_NODELABEL(hfxo), startup_time_us); -} -#endif - static int stop(const struct device *dev, clock_control_subsys_t subsys, uint32_t ctx) { @@ -810,8 +770,7 @@ static int clk_init(const struct device *dev) IRQ_CONNECT(LFRC_IRQn, DT_INST_IRQ(0, priority), nrfx_isr, nrfx_power_clock_irq_handler, 0); #endif - IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), - nrfx_isr, nrfx_power_clock_irq_handler, 0); + clock_control_nrf_common_connect_irq(); if (nrfx_clock_init(clock_event_handler) != 0) { return -EIO; diff --git a/drivers/clock_control/clock_control_nrf_common.c b/drivers/clock_control/clock_control_nrf_common.c new file mode 100644 index 000000000000..0d379563d189 --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_common.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "clock_control_nrf_common.h" +#include +#include + +#if NRFX_CHECK(NRFX_POWER_ENABLED) +#include +#endif + +#define DT_DRV_COMPAT nordic_nrf_clock + +static bool irq_connected; + +static void clock_irq_handler(void) +{ +#if NRFX_CHECK(NRFX_POWER_ENABLED) + nrfx_power_irq_handler(); +#endif + + STRUCT_SECTION_FOREACH(clock_control_nrf_irq_handler, irq) { + irq->handler(); + } + + /* temporary fix, it will be removed when all the clocks are moved to their files */ + nrfx_clock_irq_handler(); +} + +void clock_control_nrf_common_connect_irq(void) +{ + if (irq_connected) { + return; + } + irq_connected = true; + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), + nrfx_isr, clock_irq_handler, 0); +} diff --git a/drivers/clock_control/clock_control_nrf_common.h b/drivers/clock_control/clock_control_nrf_common.h new file mode 100644 index 000000000000..26df26dfba4a --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_common.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CLOCK_CONTROL_NRF_COMMON_H__ +#define CLOCK_CONTROL_NRF_COMMON_H__ + +struct clock_control_nrf_irq_handler { + void (*handler)(void); /* Clock interrupt handler */ +}; + +#define CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(name, _a) \ + STRUCT_SECTION_ITERABLE(clock_control_nrf_irq_handler, name) = { \ + .handler = _a, \ + } + +void clock_control_nrf_common_connect_irq(void); + +#endif /* CLOCK_CONTROL_NRF_COMMON_H__ */ diff --git a/drivers/clock_control/clock_control_nrf_hfclk.c b/drivers/clock_control/clock_control_nrf_hfclk.c new file mode 100644 index 000000000000..a9379b535ea5 --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_hfclk.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "nrf_clock_calibration.h" +#include +#include +#include +#include +#include "clock_control_nrf_common.h" + +LOG_MODULE_REGISTER(clock_control_hfclk, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define DT_DRV_COMPAT nordic_nrf_clock_hfclk + +#define CLOCK_DEVICE_HFCLK DEVICE_DT_GET(DT_NODELABEL(hfclk)) + +#define CTX_ONOFF BIT(6) +#define CTX_API BIT(7) +#define CTX_MASK (CTX_ONOFF | CTX_API) + +#define STATUS_MASK 0x7 +#define GET_STATUS(flags) (flags & STATUS_MASK) +#define GET_CTX(flags) (flags & CTX_MASK) + +/* Used only by HF clock */ +#define HF_USER_BT BIT(0) +#define HF_USER_GENERIC BIT(1) + +/* Helper logging macros which prepends hfclk name to the log. */ +#ifdef CONFIG_LOG +#define CLOCK_LOG(lvl, dev, ...) \ + LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \ + "hfclk" COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \ + (), (, GET_ARGS_LESS_N(1, __VA_ARGS__)))) +#else +#define CLOCK_LOG(...) +#endif + +#define ERR(dev, ...) CLOCK_LOG(ERR, dev, __VA_ARGS__) +#define WRN(dev, ...) CLOCK_LOG(WRN, dev, __VA_ARGS__) +#define INF(dev, ...) CLOCK_LOG(INF, dev, __VA_ARGS__) +#define DBG(dev, ...) CLOCK_LOG(DBG, dev, __VA_ARGS__) + +typedef void (*clk_ctrl_func_t)(void); + +typedef struct { + struct onoff_manager mgr; + clock_control_cb_t cb; + void *user_data; + uint32_t flags; +} hfclk_data_t; + +typedef struct { + clk_ctrl_func_t start; /* Clock start function */ + clk_ctrl_func_t stop; /* Clock stop function */ +#ifdef CONFIG_LOG + const char *name; +#endif +} hfclk_config_t; + +static atomic_t hfclk_users; +static uint64_t hf_start_tstamp; +static uint64_t hf_stop_tstamp; + +static int set_starting_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) { + *flags = CLOCK_CONTROL_STATUS_STARTING | ctx; + } else if (current_ctx != ctx) { + err = -EPERM; + } else { + err = -EALREADY; + } + + irq_unlock(key); + + return err; +} + +static int async_start(const struct device *dev, clock_control_cb_t cb, void *user_data, + uint32_t ctx) +{ + int err; + + err = set_starting_state(&((hfclk_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((hfclk_data_t *)dev->data)->cb = cb; + ((hfclk_data_t *)dev->data)->user_data = user_data; + + ((hfclk_config_t *)dev->config)->start(); + + return 0; +} + +static int set_off_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((current_ctx != 0) && (current_ctx != ctx)) { + err = -EPERM; + } else { + *flags = CLOCK_CONTROL_STATUS_OFF; + } + + irq_unlock(key); + + return err; +} + +static void hfclk_start(void) +{ + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) { + hf_start_tstamp = k_uptime_get(); + } + + nrfx_clock_hfclk_start(); +} + +static void hfclk_stop(void) +{ + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) { + hf_stop_tstamp = k_uptime_get(); + } + + nrfx_clock_hfclk_stop(); +} + +static int stop(const struct device *dev, uint32_t ctx) +{ + int err; + + err = set_off_state(&((hfclk_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((hfclk_config_t *)dev->config)->stop(); + + return 0; +} + +static void onoff_started_callback(const struct device *dev, clock_control_subsys_t sys, + void *user_data) +{ + ARG_UNUSED(sys); + + onoff_notify_fn notify = user_data; + + notify(&((hfclk_data_t *)dev->data)->mgr, 0); +} + +static void onoff_start(struct onoff_manager *mgr, onoff_notify_fn notify) +{ + int err; + + err = async_start(CLOCK_DEVICE_HFCLK, onoff_started_callback, notify, CTX_ONOFF); + if (err < 0) { + notify(mgr, err); + } +} + +static void onoff_stop(struct onoff_manager *mgr, onoff_notify_fn notify) +{ + int res; + + res = stop(CLOCK_DEVICE_HFCLK, CTX_ONOFF); + notify(mgr, res); +} + +static void set_on_state(uint32_t *flags) +{ + unsigned int key = irq_lock(); + + *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags); + irq_unlock(key); +} + +static void clkstarted_handle(const struct device *dev) +{ + clock_control_cb_t callback = ((hfclk_data_t *)dev->data)->cb; + + ((hfclk_data_t *)dev->data)->cb = NULL; + set_on_state(&((hfclk_data_t *)dev->data)->flags); + DBG(dev, "Clock started"); + + if (callback) { + callback(dev, NULL, ((hfclk_data_t *)dev->data)->user_data); + } +} + +static void clock_event_handler(void) +{ + const struct device *dev = CLOCK_DEVICE_HFCLK; + + /* Check needed due to anomaly 201: + * HFCLKSTARTED may be generated twice. + */ + if (GET_STATUS(((hfclk_data_t *)dev->data)->flags) == CLOCK_CONTROL_STATUS_STARTING) { + clkstarted_handle(dev); + } +} + +static void generic_hfclk_start(void) +{ + nrf_clock_hfclk_t type; + bool already_started = false; + unsigned int key = irq_lock(); + + hfclk_users |= HF_USER_GENERIC; + if (hfclk_users & HF_USER_BT) { + (void)nrfx_clock_hfclk_running_check(&type); + if (type == NRF_CLOCK_HFCLK_HIGH_ACCURACY) { + already_started = true; + /* Set on state in case clock interrupt comes and we + * want to avoid handling that. + */ + + set_on_state(&((hfclk_data_t *)CLOCK_DEVICE_HFCLK->data)->flags); + } + } + + irq_unlock(key); + + if (already_started) { + /* Clock already started by z_nrf_clock_bt_ctlr_hf_request */ + clkstarted_handle(CLOCK_DEVICE_HFCLK); + return; + } + + hfclk_start(); +} + +static void generic_hfclk_stop(void) +{ + /* It's not enough to use only atomic_and() here for synchronization, + * as the thread could be preempted right after that function but + * before hfclk_stop() is called and the preempting code could request + * the HFCLK again. Then, the HFCLK would be stopped inappropriately + * and hfclk_user would be left with an incorrect value. + */ + unsigned int key = irq_lock(); + + hfclk_users &= ~HF_USER_GENERIC; + /* Skip stopping if BT is still requesting the clock. */ + if (!(hfclk_users & HF_USER_BT)) { + hfclk_stop(); + } + + irq_unlock(key); +} + +static void blocking_start_callback(const struct device *dev, clock_control_subsys_t subsys, + void *user_data) +{ + struct k_sem *sem = user_data; + + k_sem_give(sem); +} + +void z_nrf_clock_bt_ctlr_hf_request(void) +{ + if (atomic_or(&hfclk_users, HF_USER_BT) & HF_USER_GENERIC) { + /* generic request already activated clock. */ + return; + } + + hfclk_start(); +} + +void z_nrf_clock_bt_ctlr_hf_release(void) +{ + /* It's not enough to use only atomic_and() here for synchronization, + * see the explanation in generic_hfclk_stop(). + */ + unsigned int key = irq_lock(); + + hfclk_users &= ~HF_USER_BT; + /* Skip stopping if generic is still requesting the clock. */ + if (!(hfclk_users & HF_USER_GENERIC)) { + + /* State needs to be set to OFF as BT API does not call stop API which + * normally setting this state. + */ + ((hfclk_data_t *)CLOCK_DEVICE_HFCLK->data)->flags = CLOCK_CONTROL_STATUS_OFF; + hfclk_stop(); + } + + irq_unlock(key); +} + +#if DT_NODE_EXISTS(DT_NODELABEL(hfxo)) +uint32_t z_nrf_clock_bt_ctlr_hf_get_startup_time_us(void) +{ + return DT_PROP(DT_NODELABEL(hfxo), startup_time_us); +} +#endif + +static int api_start(const struct device *dev, clock_control_subsys_t subsys, clock_control_cb_t cb, + void *user_data) +{ + ARG_UNUSED(subsys); + + return async_start(dev, cb, user_data, CTX_API); +} + +static int api_blocking_start(const struct device *dev, clock_control_subsys_t subsys) +{ + struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1); + int err; + + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return -ENOTSUP; + } + + err = api_start(dev, subsys, blocking_start_callback, &sem); + if (err < 0) { + return err; + } + + return k_sem_take(&sem, K_MSEC(500)); +} + +static int api_stop(const struct device *dev, clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return stop(dev, CTX_API); +} + +static enum clock_control_status api_get_status(const struct device *dev, + clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return GET_STATUS(((hfclk_data_t *)dev->data)->flags); +} + +static int api_request(const struct device *dev, const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + hfclk_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_request(&dev_data->mgr, cli); +} + +static int api_release(const struct device *dev, const struct nrf_clock_spec *spec) +{ + hfclk_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_release(&dev_data->mgr); +} + +static int api_cancel_or_release(const struct device *dev, const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + hfclk_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_cancel_or_release(&dev_data->mgr, cli); +} + +static int clk_init(const struct device *dev) +{ + int err; + static const struct onoff_transitions transitions = {.start = onoff_start, + .stop = onoff_stop}; + + clock_control_nrf_common_connect_irq(); + + if (nrfx_clock_hfclk_init(clock_event_handler) != 0) { + return -EIO; + } + + err = onoff_manager_init(&((hfclk_data_t *)dev->data)->mgr, &transitions); + if (err < 0) { + return err; + } + + ((hfclk_data_t *)dev->data)->flags = CLOCK_CONTROL_STATUS_OFF; + + return 0; +} + +CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(clock_control_nrf_hfclk, &nrfx_clock_hfclk_irq_handler); + +static DEVICE_API(nrf_clock_control, clock_control_api) = { + .std_api = { + .on = api_blocking_start, + .off = api_stop, + .async_on = api_start, + .get_status = api_get_status, + }, + .request = api_request, + .release = api_release, + .cancel_or_release = api_cancel_or_release, +}; + +static hfclk_data_t data; + +static const hfclk_config_t config = {.start = generic_hfclk_start, + .stop = generic_hfclk_stop, + IF_ENABLED(CONFIG_LOG, (.name = "hfclk",)) }; + +DEVICE_DT_DEFINE(DT_NODELABEL(hfclk), clk_init, NULL, &data, &config, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_api); diff --git a/drivers/clock_control/clock_control_nrf_irq_handlers.ld b/drivers/clock_control/clock_control_nrf_irq_handlers.ld new file mode 100644 index 000000000000..0836263fa577 --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_irq_handlers.ld @@ -0,0 +1,2 @@ +#include +ITERABLE_SECTION_ROM(clock_control_nrf_irq_handler, Z_LINK_ITERABLE_SUBALIGN) diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index cbfef90faa5b..4410617aa807 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -73,6 +73,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + nrf_mpu: nrf-mpu@40000000 { compatible = "nordic,nrf-mpu"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index 7951c9516ad7..3391c0a70f9f 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -61,6 +61,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index 4a1ef2bcedd8..7c91bdae2bc3 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -65,6 +65,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index d0321b857369..418d9331b642 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -69,6 +69,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index d15fbb2ae4e3..1dc8271bae7e 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -69,6 +69,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index 1513c0da8111..982461d73e9e 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -65,6 +65,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index 114399a0c28e..3ff20567c73a 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -69,6 +69,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index 18354d201972..d161211e42f7 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -65,6 +65,13 @@ status = "okay"; }; + hfclk: hfclk@40000000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index 7021b7eedeb1..9c51df186c2f 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -68,6 +68,13 @@ clock: clock@5000 { status = "okay"; }; +hfclk: hfclk@5000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x5000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; +}; + power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index be0fad16d66b..e06b02211935 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -62,6 +62,13 @@ status = "okay"; }; + hfclk: hfclk@41005000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x41005000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@41005000 { compatible = "nordic,nrf-power"; reg = <0x41005000 0x1000>; diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index 476f8415853a..66b817599e46 100644 --- a/dts/arm/nordic/nrf91_peripherals.dtsi +++ b/dts/arm/nordic/nrf91_peripherals.dtsi @@ -344,6 +344,13 @@ clock: clock@5000 { status = "okay"; }; +hfclk: hfclk@5000 { + compatible = "nordic,nrf-clock-hfclk"; + reg = <0x5000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; +}; + power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; diff --git a/dts/bindings/clock/nordic,nrf-clock-hfclk.yaml b/dts/bindings/clock/nordic,nrf-clock-hfclk.yaml new file mode 100644 index 000000000000..371acddc9826 --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-clock-hfclk.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF hfclk clock control node + +compatible: "nordic,nrf-clock-hfclk" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/clock/nordic,nrf-clock-xo.yaml b/dts/bindings/clock/nordic,nrf-clock-xo.yaml new file mode 100644 index 000000000000..3032d84f6383 --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-clock-xo.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF xo clock control node + +compatible: "nordic,nrf-clock-xo" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/vendor/nordic/nrf54l_05_10_15.dtsi b/dts/vendor/nordic/nrf54l_05_10_15.dtsi index cb2dbf0e4671..5194cfabdda7 100644 --- a/dts/vendor/nordic/nrf54l_05_10_15.dtsi +++ b/dts/vendor/nordic/nrf54l_05_10_15.dtsi @@ -639,6 +639,13 @@ status = "disabled"; }; + xo: xo@10e000 { + compatible = "nordic,nrf-clock-xo"; + reg = <0x10e000 0x1000>; + interrupts = <261 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + power: power@10e000 { compatible = "nordic,nrf-power"; reg = <0x10e000 0x1000>; diff --git a/dts/vendor/nordic/nrf54lm20a.dtsi b/dts/vendor/nordic/nrf54lm20a.dtsi index a49d6b2f9143..cd9df3d04a30 100644 --- a/dts/vendor/nordic/nrf54lm20a.dtsi +++ b/dts/vendor/nordic/nrf54lm20a.dtsi @@ -791,6 +791,13 @@ status = "disabled"; }; + xo: xo@10e000 { + compatible = "nordic,nrf-clock-xo"; + reg = <0x10e000 0x1000>; + interrupts = <261 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + power: power@10e000 { compatible = "nordic,nrf-power"; reg = <0x10e000 0x1000>; diff --git a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h index 47a3060d630e..904d74a6cea3 100644 --- a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h +++ b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h @@ -7,11 +7,14 @@ #include "device_subsys.h" #include +#if NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) static const struct device_subsys_data subsys_data[] = { +#if NRF_CLOCK_HAS_XO { .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US }, +#endif /* NRF_CLOCK_HAS_XO */ #ifndef CONFIG_SOC_NRF52832 /* On nrf52832 LF clock cannot be stopped because it leads * to RTC COUNTER register reset and that is unexpected by @@ -24,11 +27,28 @@ static const struct device_subsys_data subsys_data[] = { } #endif /* !CONFIG_SOC_NRF52832 */ }; +#endif /* NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) */ + +static const struct device_subsys_data subsys_data_hfclk[] = { + { + .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, + .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US + } +}; static const struct device_data devices[] = { +#if NRF_CLOCK_HAS_HFCLK + { + .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_hfclk), + .subsys_data = subsys_data_hfclk, + .subsys_cnt = ARRAY_SIZE(subsys_data_hfclk) + }, +#endif /* NRF_CLOCK_HAS_HFCLK */ +#if NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) { .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock), .subsys_data = subsys_data, .subsys_cnt = ARRAY_SIZE(subsys_data) } +#endif /* NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) */ }; From 9ee0d25faa646560f6f66f6668e81dc4a3c1404f Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Mon, 17 Nov 2025 15:57:57 +0100 Subject: [PATCH 3/9] [nrf fromlist] drivers: clock_control: Separated nrf xo shim from nrf clock shim. Separated clock_control_nrf_xo shim from clock_control_nrf shim. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/clock_control_nrf.c | 1 - .../clock_control/clock_control_nrf_common.c | 3 +- .../clock_control/clock_control_nrf_common.h | 8 +- drivers/clock_control/clock_control_nrf_xo.c | 562 ++++++++++++++++++ dts/vendor/nordic/nrf54lm20a.dtsi | 2 +- .../clock_control_api/src/nrf_device_subsys.h | 30 +- 7 files changed, 587 insertions(+), 20 deletions(-) create mode 100644 drivers/clock_control/clock_control_nrf_xo.c diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 975ec7bdcd52..9c016180b267 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -61,6 +61,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL clock_con zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK clock_control_nrf_hfclk.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO clock_control_nrf_xo.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_COMMON clock_control_nrf_common.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X clock_control_bl61x.c) diff --git a/drivers/clock_control/clock_control_nrf.c b/drivers/clock_control/clock_control_nrf.c index 977f7ab10949..8fb0c2ee5fbe 100644 --- a/drivers/clock_control/clock_control_nrf.c +++ b/drivers/clock_control/clock_control_nrf.c @@ -769,7 +769,6 @@ static int clk_init(const struct device *dev) #if NRF_LFRC_HAS_CALIBRATION IRQ_CONNECT(LFRC_IRQn, DT_INST_IRQ(0, priority), nrfx_isr, nrfx_power_clock_irq_handler, 0); #endif - clock_control_nrf_common_connect_irq(); if (nrfx_clock_init(clock_event_handler) != 0) { diff --git a/drivers/clock_control/clock_control_nrf_common.c b/drivers/clock_control/clock_control_nrf_common.c index 0d379563d189..7e13c7ab603c 100644 --- a/drivers/clock_control/clock_control_nrf_common.c +++ b/drivers/clock_control/clock_control_nrf_common.c @@ -36,6 +36,5 @@ void clock_control_nrf_common_connect_irq(void) } irq_connected = true; - IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), - nrfx_isr, clock_irq_handler, 0); + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), nrfx_isr, clock_irq_handler, 0); } diff --git a/drivers/clock_control/clock_control_nrf_common.h b/drivers/clock_control/clock_control_nrf_common.h index 26df26dfba4a..fa476bd05049 100644 --- a/drivers/clock_control/clock_control_nrf_common.h +++ b/drivers/clock_control/clock_control_nrf_common.h @@ -7,12 +7,12 @@ #define CLOCK_CONTROL_NRF_COMMON_H__ struct clock_control_nrf_irq_handler { - void (*handler)(void); /* Clock interrupt handler */ + void (*handler)(void); /* Clock interrupt handler */ }; -#define CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(name, _a) \ - STRUCT_SECTION_ITERABLE(clock_control_nrf_irq_handler, name) = { \ - .handler = _a, \ +#define CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(name, _a) \ + STRUCT_SECTION_ITERABLE(clock_control_nrf_irq_handler, name) = { \ + .handler = _a, \ } void clock_control_nrf_common_connect_irq(void); diff --git a/drivers/clock_control/clock_control_nrf_xo.c b/drivers/clock_control/clock_control_nrf_xo.c new file mode 100644 index 000000000000..8cda053a201f --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_xo.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2016-2025 Nordic Semiconductor ASA + * Copyright (c) 2016 Vinayak Kariappa Chettimada + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "nrf_clock_calibration.h" +#include +#include +#include +#include +#include +#include "clock_control_nrf_common.h" + +LOG_MODULE_REGISTER(clock_control_xo, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define DT_DRV_COMPAT nordic_nrf_clock_xo + +#define CLOCK_DEVICE_XO DEVICE_DT_GET(DT_NODELABEL(xo)) + +#define CTX_ONOFF BIT(6) +#define CTX_API BIT(7) +#define CTX_MASK (CTX_ONOFF | CTX_API) + +#define STATUS_MASK 0x7 +#define GET_STATUS(flags) (flags & STATUS_MASK) +#define GET_CTX(flags) (flags & CTX_MASK) + +/* Used only by HF clock */ +#define XO_USER_BT BIT(0) +#define XO_USER_GENERIC BIT(1) + +/* Helper logging macros which prepends subsys name to the log. */ +#ifdef CONFIG_LOG +#define CLOCK_LOG(lvl, dev, ...) \ + LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \ + "xo" \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__),\ + (), (, GET_ARGS_LESS_N(1, __VA_ARGS__)))) +#else +#define CLOCK_LOG(...) +#endif + +#define ERR(dev, ...) CLOCK_LOG(ERR, dev, __VA_ARGS__) +#define WRN(dev, ...) CLOCK_LOG(WRN, dev, __VA_ARGS__) +#define INF(dev, ...) CLOCK_LOG(INF, dev, __VA_ARGS__) +#define DBG(dev, ...) CLOCK_LOG(DBG, dev, __VA_ARGS__) + +typedef void (*clk_ctrl_xo_func_t)(void); + +typedef struct { + struct onoff_manager mgr; + clock_control_cb_t cb; + void *user_data; + uint32_t flags; +} xo_data_t; + +typedef struct { + clk_ctrl_xo_func_t start; /* Clock start function */ + clk_ctrl_xo_func_t stop; /* Clock stop function */ +#ifdef CONFIG_LOG + const char *name; +#endif +} xo_config_t; + +static atomic_t xo_users; +static uint64_t xo_start_tstamp; +static uint64_t xo_stop_tstamp; + +static int set_starting_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) { + *flags = CLOCK_CONTROL_STATUS_STARTING | ctx; + } else if (current_ctx != ctx) { + err = -EPERM; + } else { + err = -EALREADY; + } + + irq_unlock(key); + + return err; +} + +static int async_start(const struct device *dev, clock_control_cb_t cb, + void *user_data, uint32_t ctx) +{ + int err; + + err = set_starting_state(&((xo_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((xo_data_t *)dev->data)->cb = cb; + ((xo_data_t *)dev->data)->user_data = user_data; + + ((xo_config_t *)dev->config)->start(); + + return 0; +} + +static int set_off_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((current_ctx != 0) && (current_ctx != ctx)) { + err = -EPERM; + } else { + *flags = CLOCK_CONTROL_STATUS_OFF; + } + + irq_unlock(key); + + return err; +} + +static void set_on_state(uint32_t *flags) +{ + unsigned int key = irq_lock(); + + *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags); + irq_unlock(key); +} + +static int stop(const struct device *dev, uint32_t ctx) +{ + int err; + + err = set_off_state(&((xo_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((xo_config_t *)dev->config)->stop(); + + return 0; +} + +static void xo_start(void) +{ + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) { + xo_start_tstamp = k_uptime_get(); + } + + nrfx_clock_xo_start(); +} + +static void xo_stop(void) +{ + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) { + xo_stop_tstamp = k_uptime_get(); + } + + nrfx_clock_xo_stop(); +} + +#ifdef CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION + +static void nrf54l_errata_30_workaround(void) +{ + while (FIELD_GET(CLOCK_XO_STAT_STATE_Msk, NRF_CLOCK->XO.STAT) != + CLOCK_XO_STAT_STATE_Running) { + } + const uint32_t higher_bits = *((volatile uint32_t *)0x50120820UL) & 0xFFFFFFC0; + *((volatile uint32_t *)0x50120864UL) = 1 | BIT(31); + *((volatile uint32_t *)0x50120848UL) = 1; + uint32_t off_abs = 24; + + while (off_abs >= 24) { + *((volatile uint32_t *)0x50120844UL) = 1; + while (((*((volatile uint32_t *)0x50120840UL)) & (1 << 16)) != 0) { + } + const uint32_t current_cal = *((volatile uint32_t *)0x50120820UL) & 0x3F; + const uint32_t cal_result = *((volatile uint32_t *)0x50120840UL) & 0x7FF; + int32_t off = 1024 - cal_result; + + off_abs = (off < 0) ? -off : off; + + if (off >= 24 && current_cal < 0x3F) { + *((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal + 1); + } else if (off <= -24 && current_cal > 0) { + *((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal - 1); + } + } + + *((volatile uint32_t *)0x50120848UL) = 0; + *((volatile uint32_t *)0x50120864UL) = 0; +} + +#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD + +static struct onoff_client hf_cal_cli; + +static void calibration_finished_callback(struct onoff_manager *mgr, + struct onoff_client *cli, + uint32_t state, + int res) +{ + (void)onoff_cancel_or_release(mgr, cli); +} + +static void calibration_handler(struct k_timer *timer) +{ + nrf_clock_xo_t clk_src; + + bool ret = nrfx_clock_xo_running_check(&clk_src); + + if (ret && (clk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY)) { + return; + } + + sys_notify_init_callback(&hf_cal_cli.notify, calibration_finished_callback); + (void)onoff_request(&((xo_data_t *)CLOCK_DEVICE_XO->data)->mgr, &hf_cal_cli); +} + +static K_TIMER_DEFINE(calibration_timer, calibration_handler, NULL); + +static int calibration_init(void) +{ + k_timer_start(&calibration_timer, + K_NO_WAIT, + K_MSEC(CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD)); + + return 0; +} + +SYS_INIT(calibration_init, APPLICATION, 0); + +#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD */ +#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION */ + +static void clkstarted_handle(const struct device *dev) +{ +#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION + if (nrf54l_errata_30()) { + nrf54l_errata_30_workaround(); + } +#endif + + clock_control_cb_t callback = ((xo_data_t *)dev->data)->cb; + void *user_data = ((xo_data_t *)dev->data)->user_data; + + ((xo_data_t *)dev->data)->cb = NULL; + set_on_state(&((xo_data_t *)dev->data)->flags); + DBG(dev, "Clock started"); + + if (callback) { + callback(dev, NULL, user_data); + } +} + +static void generic_xo_start(void) +{ + nrf_clock_hfclk_t type; + bool already_started = false; + unsigned int key = irq_lock(); + + xo_users |= XO_USER_GENERIC; + if (xo_users & XO_USER_BT) { + (void)nrfx_clock_xo_running_check(&type); + if (type == NRF_CLOCK_HFCLK_HIGH_ACCURACY) { + already_started = true; + /* Set on state in case clock interrupt comes and we + * want to avoid handling that. + */ + set_on_state( + &((xo_data_t *)CLOCK_DEVICE_XO->data)->flags); + } + } + + irq_unlock(key); + + if (already_started) { + /* Clock already started by z_nrf_clock_bt_ctlr_hf_request */ + clkstarted_handle(CLOCK_DEVICE_XO); + return; + } + + xo_start(); +} + +static void generic_xo_stop(void) +{ + /* It's not enough to use only atomic_and() here for synchronization, + * as the thread could be preempted right after that function but + * before xo_stop() is called and the preempting code could request + * the XO again. Then, the XO would be stopped inappropriately + * and xo_user would be left with an incorrect value. + */ + unsigned int key = irq_lock(); + + xo_users &= ~XO_USER_GENERIC; + /* Skip stopping if BT is still requesting the clock. */ + if (!(xo_users & XO_USER_BT)) { + xo_stop(); + } + + irq_unlock(key); +} + +static void onoff_started_callback(const struct device *dev, + clock_control_subsys_t sys, + void *user_data) +{ + ARG_UNUSED(sys); + + onoff_notify_fn notify = user_data; + + notify(&(((xo_data_t *)dev->data)->mgr), 0); +} + + +static void onoff_start(struct onoff_manager *mgr, + onoff_notify_fn notify) +{ + int err; + + err = async_start(CLOCK_DEVICE_XO, onoff_started_callback, notify, CTX_ONOFF); + if (err < 0) { + notify(mgr, err); + } +} + +static void onoff_stop(struct onoff_manager *mgr, + onoff_notify_fn notify) +{ + int res; + + res = stop(CLOCK_DEVICE_XO, CTX_ONOFF); + notify(mgr, res); +} + +static void clock_event_handler(nrfx_clock_xo_evt_type_t event) +{ + const struct device *dev = CLOCK_DEVICE_XO; + + switch (event) { +#if NRF_CLOCK_HAS_XO_TUNE + case NRFX_CLOCK_XO_EVT_XO_TUNED: + clkstarted_handle(dev); + break; + case NRFX_CLOCK_XO_EVT_XO_TUNE_ERROR: + case NRFX_CLOCK_XO_EVT_XO_TUNE_FAILED: + /* No processing needed. */ + break; + case NRFX_CLOCK_XO_EVT_HFCLK_STARTED: + /* HFCLK is stable after XOTUNED event. + * HFCLK_STARTED means only that clock has been started. + */ + break; +#else + /* HFCLK started should be used only if tune operation is done implicitly. */ + case NRFX_CLOCK_XO_EVT_HFCLK_STARTED: + { + /* Check needed due to anomaly 201: + * HFCLKSTARTED may be generated twice. + */ + if (GET_STATUS(((xo_data_t *)dev->data)->flags) + == CLOCK_CONTROL_STATUS_STARTING) { + clkstarted_handle(dev); + } + + break; + } +#endif + +#if NRF_CLOCK_HAS_PLL + case NRFX_CLOCK_XO_EVT_PLL_STARTED: + /* No processing needed. */ + break; +#endif + default: + __ASSERT_NO_MSG(0); + break; + } +} + +static void blocking_start_callback(const struct device *dev, + clock_control_subsys_t subsys, + void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(subsys); + + struct k_sem *sem = user_data; + + k_sem_give(sem); +} + +void z_nrf_clock_bt_ctlr_hf_request(void) +{ + if (atomic_or(&xo_users, XO_USER_BT) & XO_USER_GENERIC) { + /* generic request already activated clock. */ + return; + } + + xo_start(); +} + +void z_nrf_clock_bt_ctlr_hf_release(void) +{ + /* It's not enough to use only atomic_and() here for synchronization, + * see the explanation in generic_hfclk_stop(). + */ + unsigned int key = irq_lock(); + + xo_users &= ~XO_USER_BT; + /* Skip stopping if generic is still requesting the clock. */ + if (!(xo_users & XO_USER_GENERIC)) { + + /* State needs to be set to OFF as BT API does not call stop API which + * normally setting this state. + */ + ((xo_data_t *)CLOCK_DEVICE_XO->data)->flags = CLOCK_CONTROL_STATUS_OFF; + xo_stop(); + } + + irq_unlock(key); +} + +#if DT_NODE_EXISTS(DT_NODELABEL(hfxo)) +uint32_t z_nrf_clock_bt_ctlr_hf_get_startup_time_us(void) +{ + return DT_PROP(DT_NODELABEL(hfxo), startup_time_us); +} +#endif + +static int api_start(const struct device *dev, clock_control_subsys_t subsys, + clock_control_cb_t cb, void *user_data) +{ + ARG_UNUSED(subsys); + + return async_start(dev, cb, user_data, CTX_API); +} + +static int api_blocking_start(const struct device *dev, + clock_control_subsys_t subsys) +{ + struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1); + int err; + + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return -ENOTSUP; + } + + err = api_start(dev, subsys, blocking_start_callback, &sem); + if (err < 0) { + return err; + } + + return k_sem_take(&sem, K_MSEC(500)); +} + +static int api_stop(const struct device *dev, clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return stop(dev, CTX_API); +} + +static enum clock_control_status api_get_status(const struct device *dev, + clock_control_subsys_t subsys) +{ + return GET_STATUS(((xo_data_t *)dev->data)->flags); +} + +static int api_request(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + xo_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_request(&dev_data->mgr, cli); +} + +static int api_release(const struct device *dev, + const struct nrf_clock_spec *spec) +{ + xo_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_release(&dev_data->mgr); +} + +static int api_cancel_or_release(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + xo_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_cancel_or_release(&dev_data->mgr, cli); +} + +static int clk_init(const struct device *dev) +{ + int err; + static const struct onoff_transitions transitions = { + .start = onoff_start, + .stop = onoff_stop + }; + + clock_control_nrf_common_connect_irq(); + + if (nrfx_clock_xo_init(clock_event_handler) != 0) { + return -EIO; + } + + err = onoff_manager_init(&((xo_data_t *)dev->data)->mgr, + &transitions); + if (err < 0) { + return err; + } + + ((xo_data_t *)dev->data)->flags = CLOCK_CONTROL_STATUS_OFF; + + return 0; +} + +CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(clock_control_nrf_xo, + &nrfx_clock_xo_irq_handler); + +static DEVICE_API(nrf_clock_control, clock_control_api) = { + .std_api = { + .on = api_blocking_start, + .off = api_stop, + .async_on = api_start, + .get_status = api_get_status, + }, + .request = api_request, + .release = api_release, + .cancel_or_release = api_cancel_or_release, +}; + +static xo_data_t data; + +static const xo_config_t config = { + .start = generic_xo_start, + .stop = generic_xo_stop, + IF_ENABLED(CONFIG_LOG, (.name = "xo",)) +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(xo), clk_init, NULL, + &data, &config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &clock_control_api); diff --git a/dts/vendor/nordic/nrf54lm20a.dtsi b/dts/vendor/nordic/nrf54lm20a.dtsi index cd9df3d04a30..ce8ff6b08e61 100644 --- a/dts/vendor/nordic/nrf54lm20a.dtsi +++ b/dts/vendor/nordic/nrf54lm20a.dtsi @@ -794,7 +794,7 @@ xo: xo@10e000 { compatible = "nordic,nrf-clock-xo"; reg = <0x10e000 0x1000>; - interrupts = <261 NRF_DEFAULT_IRQ_PRIORITY>; + interrupts = <270 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; }; diff --git a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h index 904d74a6cea3..5b48d96aa32e 100644 --- a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h +++ b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h @@ -7,15 +7,8 @@ #include "device_subsys.h" #include -#if NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) -static const struct device_subsys_data subsys_data[] = { -#if NRF_CLOCK_HAS_XO - { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, - .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US - }, -#endif /* NRF_CLOCK_HAS_XO */ #ifndef CONFIG_SOC_NRF52832 +static const struct device_subsys_data subsys_data[] = { /* On nrf52832 LF clock cannot be stopped because it leads * to RTC COUNTER register reset and that is unexpected by * system clock which is disrupted and may hang in the test. @@ -25,9 +18,8 @@ static const struct device_subsys_data subsys_data[] = { .startup_us = (CLOCK_CONTROL_NRF_K32SRC == NRF_CLOCK_LFCLK_RC) ? 1000 : 500000 } -#endif /* !CONFIG_SOC_NRF52832 */ }; -#endif /* NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) */ +#endif /* !CONFIG_SOC_NRF52832 */ static const struct device_subsys_data subsys_data_hfclk[] = { { @@ -36,6 +28,13 @@ static const struct device_subsys_data subsys_data_hfclk[] = { } }; +static const struct device_subsys_data subsys_data_xo[] = { + { + .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, + .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US + } +}; + static const struct device_data devices[] = { #if NRF_CLOCK_HAS_HFCLK { @@ -44,11 +43,18 @@ static const struct device_data devices[] = { .subsys_cnt = ARRAY_SIZE(subsys_data_hfclk) }, #endif /* NRF_CLOCK_HAS_HFCLK */ -#if NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) +#if NRF_CLOCK_HAS_XO + { + .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_xo), + .subsys_data = subsys_data_xo, + .subsys_cnt = ARRAY_SIZE(subsys_data_xo) + }, +#endif /* NRF_CLOCK_HAS_XO */ +#if !defined(CONFIG_SOC_NRF52832) { .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock), .subsys_data = subsys_data, .subsys_cnt = ARRAY_SIZE(subsys_data) } -#endif /* NRF_CLOCK_HAS_XO || !defined(CONFIG_SOC_NRF52832) */ +#endif /* !defined(CONFIG_SOC_NRF52832) */ }; From 1fa000e93ad6bb8c7243a9185384459c44df5dfd Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Mon, 17 Nov 2025 15:57:58 +0100 Subject: [PATCH 4/9] [nrf fromlist] drivers: clock_control: Separated nrf lfclk shim from nrf clock shim. Separated clock_control_nrf_lfclk shim from clock_control_nrf shim. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- .../nrf54l_10_15_cpuapp_common.dtsi | 4 + .../bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi | 4 + .../nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts | 4 + .../nrf54lm20bsim_nrf54lm20a_cpuapp.dts | 4 + .../nrf54l_05_10_15_cpuapp_common.dtsi | 4 + boards/nordic/nrf54l15dk/pre_dt_board.cmake | 6 + .../nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi | 4 + .../panb611evb_nrf54l15_cpuapp_common.dtsi | 4 + .../raytac_an54l15q_db_cpuapp_common.dtsi | 4 + .../ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts | 4 + drivers/clock_control/CMakeLists.txt | 3 +- drivers/clock_control/Kconfig.nrf | 16 +- drivers/clock_control/clock_control_nrf.c | 127 +-- .../clock_control/clock_control_nrf_common.c | 4 + .../clock_control/clock_control_nrf_lfclk.c | 722 ++++++++++-------- .../clock_control/clock_control_nrfs_lfclk.c | 436 +++++++++++ drivers/clock_control/nrf_clock_calibration.c | 25 +- drivers/clock_control/nrf_clock_calibration.h | 4 +- dts/arm/nordic/nrf51822.dtsi | 7 + dts/arm/nordic/nrf52805.dtsi | 7 + dts/arm/nordic/nrf52810.dtsi | 7 + dts/arm/nordic/nrf52811.dtsi | 7 + dts/arm/nordic/nrf52820.dtsi | 7 + dts/arm/nordic/nrf52832.dtsi | 7 + dts/arm/nordic/nrf52833.dtsi | 7 + dts/arm/nordic/nrf52840.dtsi | 7 + .../nordic/nrf5340_cpuapp_peripherals.dtsi | 7 + dts/arm/nordic/nrf5340_cpunet.dtsi | 7 + dts/arm/nordic/nrf91_peripherals.dtsi | 7 + .../clock/nordic,nrf-clock-lfclk.yaml | 15 + dts/bindings/clock/nordic,nrf-lfclk.yaml | 2 +- dts/vendor/nordic/nrf54h20.dtsi | 3 +- dts/vendor/nordic/nrf54l_05_10_15.dtsi | 7 + dts/vendor/nordic/nrf54lm20a.dtsi | 7 + .../clock_control_api/src/nrf_device_subsys.h | 40 +- .../src/test_clock_control.c | 16 +- .../nrf_clock_control/src/main.c | 4 +- 37 files changed, 1051 insertions(+), 499 deletions(-) create mode 100644 boards/nordic/nrf54l15dk/pre_dt_board.cmake create mode 100644 drivers/clock_control/clock_control_nrfs_lfclk.c create mode 100644 dts/bindings/clock/nordic,nrf-clock-lfclk.yaml diff --git a/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi b/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi index 3e2b19c68a1a..eeeff6b7ec0e 100644 --- a/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi +++ b/boards/ezurio/bl54l15_dvk/nrf54l_10_15_cpuapp_common.dtsi @@ -96,6 +96,10 @@ status = "okay"; }; +&lfclk { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi b/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi index fd78f2d08998..1c0bae280071 100644 --- a/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi +++ b/boards/ezurio/bl54l15u_dvk/nrf54l15_cpuapp_common.dtsi @@ -96,6 +96,10 @@ status = "okay"; }; +&lfclk { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts index 0640c6b2adc0..a1c2f4bd4d15 100644 --- a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts +++ b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts @@ -139,3 +139,7 @@ &xo { status = "okay"; }; + +&lfclk { + status = "okay"; +}; diff --git a/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts b/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts index e65262bae057..19efa0cdbfec 100644 --- a/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts +++ b/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts @@ -146,3 +146,7 @@ &xo { status = "okay"; }; + +&lfclk { + status = "okay"; +}; diff --git a/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi b/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi index dcae050111ac..4b7409cbeaf0 100644 --- a/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi +++ b/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi @@ -105,6 +105,10 @@ status = "okay"; }; +&lfclk { + status = "okay"; +}; + &gpregret1 { status = "okay"; diff --git a/boards/nordic/nrf54l15dk/pre_dt_board.cmake b/boards/nordic/nrf54l15dk/pre_dt_board.cmake new file mode 100644 index 000000000000..d675eacdcb14 --- /dev/null +++ b/boards/nordic/nrf54l15dk/pre_dt_board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - power@X010e000 & clock@X010e000 & xo@X010e000 & lfclk@X010e000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi index 70ee2d89a05c..99877b8aa85c 100644 --- a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi +++ b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi @@ -134,6 +134,10 @@ status = "okay"; }; +&lfclk { + status = "okay"; +}; + &ieee802154 { status = "okay"; }; diff --git a/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi b/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi index a4e0b7add0fb..1a6b2f6050cc 100644 --- a/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi +++ b/boards/panasonic/panb611evb/panb611evb_nrf54l15_cpuapp_common.dtsi @@ -95,6 +95,10 @@ status = "okay"; }; +&lfclk { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi b/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi index bf42a5b3a1fa..680329d3f6d3 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi +++ b/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi @@ -96,6 +96,10 @@ status = "okay"; }; +&lfclk { + status = "okay"; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts b/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts index ef7455d3a5df..15abb061895b 100644 --- a/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts +++ b/boards/we/ophelia4ev/ophelia4ev_nrf54l15_cpuapp.dts @@ -103,6 +103,10 @@ status = "okay"; }; +&lfclk { + status = "okay"; +}; + &spi00 { status = "okay"; diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 9c016180b267..1fc767aa2fdd 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -58,10 +58,11 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_FLL16M clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF54H_HFXO clock_control_nrf54h_hfxo.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HSFLL_LOCAL clock_control_nrf_hsfll_local.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL clock_control_nrf_iron_hsfll_local.c) -zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRFS_LFCLK clock_control_nrfs_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK clock_control_nrf_hfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO clock_control_nrf_xo.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_COMMON clock_control_nrf_common.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X clock_control_bl61x.c) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index f8622eab5aba..2f970ac5e783 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -307,21 +307,21 @@ config CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL_DVFS_TIMEOUT_MS endif # CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL -config CLOCK_CONTROL_NRF_LFCLK +config CLOCK_CONTROL_NRFS_LFCLK bool "NRF LFCLK driver support" - depends on DT_HAS_NORDIC_NRF_LFCLK_ENABLED + depends on DT_HAS_NORDIC_NRFS_LFCLK_ENABLED select NRFS select NRFS_CLOCK_SERVICE_ENABLED select CLOCK_CONTROL_NRF2_COMMON default y -if CLOCK_CONTROL_NRF_LFCLK +if CLOCK_CONTROL_NRFS_LFCLK -config CLOCK_CONTROL_NRF_LFCLK_CLOCK_TIMEOUT_MS +config CLOCK_CONTROL_NRFS_LFCLK_CLOCK_TIMEOUT_MS int "Timeout waiting for nrfs clock service callback in milliseconds" default 1000 -endif # CLOCK_CONTROL_NRF_LFCLK +endif # CLOCK_CONTROL_NRFS_LFCLK config CLOCK_CONTROL_NRF_COMMON bool @@ -338,6 +338,12 @@ config CLOCK_CONTROL_NRF_XO select CLOCK_CONTROL_NRF_COMMON default y +config CLOCK_CONTROL_NRF_LFCLK + bool "NRF LFCLK driver support" + depends on DT_HAS_NORDIC_NRF_CLOCK_LFCLK_ENABLED + select CLOCK_CONTROL_NRF_COMMON + default y + config CLOCK_CONTROL_NRF_AUXPLL bool "nRF Auxiliary PLL driver" default y diff --git a/drivers/clock_control/clock_control_nrf.c b/drivers/clock_control/clock_control_nrf.c index 8fb0c2ee5fbe..2ffe5cb694e9 100644 --- a/drivers/clock_control/clock_control_nrf.c +++ b/drivers/clock_control/clock_control_nrf.c @@ -538,129 +538,6 @@ static void onoff_start(struct onoff_manager *mgr, } } -/** @brief Wait for LF clock availability or stability. - * - * If LF clock source is SYNTH or RC then there is no distinction between - * availability and stability. In case of XTAL source clock, system is initially - * starting RC and then seamlessly switches to XTAL. Running RC means clock - * availability and running target source means stability, That is because - * significant difference in startup time (<1ms vs >200ms). - * - * In order to get event/interrupt when RC is ready (allowing CPU sleeping) two - * stage startup sequence is used. Initially, LF source is set to RC and when - * LFSTARTED event is handled it is reconfigured to the target source clock. - * This approach is implemented in nrfx_clock driver and utilized here. - * - * @param mode Start mode. - */ -static void lfclk_spinwait(enum nrf_lfclk_start_mode mode) -{ - static const nrf_clock_domain_t d = NRF_CLOCK_DOMAIN_LFCLK; - static const nrf_clock_lfclk_t target_type = - /* For sources XTAL, EXT_LOW_SWING, and EXT_FULL_SWING, - * NRF_CLOCK_LFCLK_XTAL is returned as the type of running clock. - */ - (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL) || - IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING) || - IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING)) - ? NRF_CLOCK_LFCLK_XTAL - : CLOCK_CONTROL_NRF_K32SRC; - nrf_clock_lfclk_t type; - - if ((mode == CLOCK_CONTROL_NRF_LF_START_AVAILABLE) && - (target_type == NRF_CLOCK_LFCLK_XTAL) && - (nrf_clock_lf_srccopy_get(NRF_CLOCK) == CLOCK_CONTROL_NRF_K32SRC)) { - /* If target clock source is using XTAL then due to two-stage - * clock startup sequence, RC might already be running. - * It can be determined by checking current LFCLK source. If it - * is set to the target clock source then it means that RC was - * started. - */ - return; - } - - bool isr_mode = k_is_in_isr() || k_is_pre_kernel(); - int key = isr_mode ? irq_lock() : 0; - - if (!isr_mode) { - nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK); - } - - while (!(nrfx_clock_is_running(d, (void *)&type) - && ((type == target_type) - || (mode == CLOCK_CONTROL_NRF_LF_START_AVAILABLE)))) { - /* Synth source start is almost instant and LFCLKSTARTED may - * happen before calling idle. That would lead to deadlock. - */ - if (!IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH)) { - if (isr_mode || !IS_ENABLED(CONFIG_MULTITHREADING)) { - k_cpu_atomic_idle(key); - } else { - k_msleep(1); - } - } - - /* Clock interrupt is locked, LFCLKSTARTED is handled here. */ - if ((target_type == NRF_CLOCK_LFCLK_XTAL) - && (nrf_clock_lf_src_get(NRF_CLOCK) == NRF_CLOCK_LFCLK_RC) - && nrf_clock_event_check(NRF_CLOCK, - NRF_CLOCK_EVENT_LFCLKSTARTED)) { - nrf_clock_event_clear(NRF_CLOCK, - NRF_CLOCK_EVENT_LFCLKSTARTED); - nrf_clock_lf_src_set(NRF_CLOCK, - CLOCK_CONTROL_NRF_K32SRC); - - /* Clear pending interrupt, otherwise new clock event - * would not wake up from idle. - */ - NVIC_ClearPendingIRQ(DT_INST_IRQN(0)); - nrf_clock_task_trigger(NRF_CLOCK, - NRF_CLOCK_TASK_LFCLKSTART); - } - } - - if (isr_mode) { - irq_unlock(key); - } else { - nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK); - } -} - -void z_nrf_clock_control_lf_on(enum nrf_lfclk_start_mode start_mode) -{ - static atomic_t on; - static struct onoff_client cli; - - if (atomic_set(&on, 1) == 0) { - int err; - struct onoff_manager *mgr = - get_onoff_manager(CLOCK_DEVICE, - CLOCK_CONTROL_NRF_TYPE_LFCLK); - - sys_notify_init_spinwait(&cli.notify); - err = onoff_request(mgr, &cli); - __ASSERT_NO_MSG(err >= 0); - } - - /* In case of simulated board leave immediately. */ - if (IS_ENABLED(CONFIG_SOC_SERIES_BSIM_NRFXX)) { - return; - } - - switch (start_mode) { - case CLOCK_CONTROL_NRF_LF_START_AVAILABLE: - case CLOCK_CONTROL_NRF_LF_START_STABLE: - lfclk_spinwait(start_mode); - break; - - case CLOCK_CONTROL_NRF_LF_START_NOWAIT: - break; - - default: - __ASSERT_NO_MSG(false); - } -} - static void clock_event_handler(nrfx_clock_evt_type_t event) { const struct device *dev = CLOCK_DEVICE; @@ -778,9 +655,7 @@ static int clk_init(const struct device *dev) hfclkaudio_init(); if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { - struct nrf_clock_control_data *data = dev->data; - - z_nrf_clock_calibration_init(data->mgr); + z_nrf_clock_calibration_init(); } nrfx_clock_enable(); diff --git a/drivers/clock_control/clock_control_nrf_common.c b/drivers/clock_control/clock_control_nrf_common.c index 7e13c7ab603c..8c7b5aab17f1 100644 --- a/drivers/clock_control/clock_control_nrf_common.c +++ b/drivers/clock_control/clock_control_nrf_common.c @@ -36,5 +36,9 @@ void clock_control_nrf_common_connect_irq(void) } irq_connected = true; +#if NRF_LFRC_HAS_CALIBRATION + IRQ_CONNECT(LFRC_IRQn, DT_INST_IRQ(0, priority), nrfx_isr, clock_irq_handler, 0); +#endif + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), nrfx_isr, clock_irq_handler, 0); } diff --git a/drivers/clock_control/clock_control_nrf_lfclk.c b/drivers/clock_control/clock_control_nrf_lfclk.c index 9551fb4e6361..01d33d60a855 100644 --- a/drivers/clock_control/clock_control_nrf_lfclk.c +++ b/drivers/clock_control/clock_control_nrf_lfclk.c @@ -1,436 +1,520 @@ /* - * Copyright (c) 2024 Nordic Semiconductor ASA + * Copyright (c) 2016-2025 Nordic Semiconductor ASA + * Copyright (c) 2016 Vinayak Kariappa Chettimada + * * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT nordic_nrf_lfclk - -#include "clock_control_nrf2_common.h" -#include +#include +#include +#include #include -#include -#include - +#include "nrf_clock_calibration.h" +#include "clock_control_nrf_common.h" +#include #include -LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); - -BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, - "multiple instances not supported"); +#include +#include + +LOG_MODULE_REGISTER(clock_control_lfclk, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define DT_DRV_COMPAT nordic_nrf_clock_lfclk + +#define CTX_ONOFF BIT(6) +#define CTX_API BIT(7) +#define CTX_MASK (CTX_ONOFF | CTX_API) + +#define STATUS_MASK 0x7 +#define GET_STATUS(flags) (flags & STATUS_MASK) +#define GET_CTX(flags) (flags & CTX_MASK) + +/* Helper logging macros which prepends subsys name to the log. */ +#ifdef CONFIG_LOG +#define CLOCK_LOG(lvl, dev, ...) \ + LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \ + "lfclk" \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__),\ + (), (, GET_ARGS_LESS_N(1, __VA_ARGS__)))) +#else +#define CLOCK_LOG(...) +#endif + +#define ERR(dev, ...) CLOCK_LOG(ERR, dev, __VA_ARGS__) +#define WRN(dev, ...) CLOCK_LOG(WRN, dev, __VA_ARGS__) +#define INF(dev, ...) CLOCK_LOG(INF, dev, __VA_ARGS__) +#define DBG(dev, ...) CLOCK_LOG(DBG, dev, __VA_ARGS__) + +#define CLOCK_DEVICE_LFCLK DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk) +#if NRF_CLOCK_HAS_HFCLK +#define CLOCK_DEVICE_HF DEVICE_DT_GET_ONE(nordic_nrf_clock_hfclk) +#else /* NRF_CLOCK_HAS_XO */ +#define CLOCK_DEVICE_HF DEVICE_DT_GET_ONE(nordic_nrf_clock_xo) +#endif + +typedef void (*clk_ctrl_func_t)(void); + +typedef struct { + struct onoff_manager mgr; + clock_control_cb_t cb; + void *user_data; + uint32_t flags; +} lfclk_data_t; + +typedef struct { + clk_ctrl_func_t start; /* Clock start function */ + clk_ctrl_func_t stop; /* Clock stop function */ +#ifdef CONFIG_LOG + const char *name; +#endif +} lfclk_config_t; + +#if CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH +/* Client to request HFXO to synthesize low frequency clock. */ +static struct onoff_client lfsynth_cli; +#endif + +static int set_off_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); -#define LFCLK_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo) + if ((current_ctx != 0) && (current_ctx != ctx)) { + err = -EPERM; + } else { + *flags = CLOCK_CONTROL_STATUS_OFF; + } -#define LFCLK_LFRC_ACCURACY DT_INST_PROP(0, lfrc_accuracy_ppm) -#define LFCLK_HFXO_ACCURACY DT_PROP(LFCLK_HFXO_NODE, accuracy_ppm) -#define LFCLK_LFLPRC_STARTUP_TIME_US DT_INST_PROP(0, lflprc_startup_time_us) -#define LFCLK_LFRC_STARTUP_TIME_US DT_INST_PROP(0, lfrc_startup_time_us) + irq_unlock(key); -#define LFCLK_MAX_OPTS 4 -#define LFCLK_DEF_OPTS 2 + return err; +} -#define NRFS_CLOCK_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF_LFCLK_CLOCK_TIMEOUT_MS) +static int set_starting_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) { + *flags = CLOCK_CONTROL_STATUS_STARTING | ctx; + } else if (current_ctx != ctx) { + err = -EPERM; + } else { + err = -EALREADY; + } -#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + irq_unlock(key); -/* Clock options sorted from highest to lowest power consumption. - * - Clock synthesized from a high frequency clock - * - Internal RC oscillator - * - External clock. These are inserted into the list at driver initialization. - * Set to one of the following: - * - XTAL. Low or High precision - * - External sine or square wave - */ -static struct clock_options { - uint16_t accuracy : 15; - uint16_t precision : 1; - nrfs_clock_src_t src; -} clock_options[LFCLK_MAX_OPTS] = { - { - /* NRFS will request FLL16M use HFXO in bypass mode if SYNTH src is used */ - .accuracy = LFCLK_HFXO_ACCURACY, - .precision = 1, - .src = NRFS_CLOCK_SRC_LFCLK_SYNTH, - }, - { - .accuracy = LFCLK_LFRC_ACCURACY, - .precision = 0, - .src = NRFS_CLOCK_SRC_LFCLK_LFRC, - }, - /* Remaining options are populated on lfclk_init */ -}; + return err; +} -struct lfclk_dev_data { - STRUCT_CLOCK_CONFIG(lfclk, ARRAY_SIZE(clock_options)) clk_cfg; - struct k_timer timer; - uint16_t max_accuracy; - uint8_t clock_options_cnt; - uint32_t hfxo_startup_time_us; - uint32_t lfxo_startup_time_us; -}; +static void set_on_state(uint32_t *flags) +{ + unsigned int key = irq_lock(); -struct lfclk_dev_config { - uint32_t fixed_frequency; -}; + *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags); + irq_unlock(key); +} -static int lfosc_get_accuracy(uint16_t *accuracy) +static void clkstarted_handle(const struct device *dev) { - switch (nrf_bicr_lfosc_accuracy_get(BICR)) { - case NRF_BICR_LFOSC_ACCURACY_500PPM: - *accuracy = 500U; - break; - case NRF_BICR_LFOSC_ACCURACY_250PPM: - *accuracy = 250U; - break; - case NRF_BICR_LFOSC_ACCURACY_150PPM: - *accuracy = 150U; - break; - case NRF_BICR_LFOSC_ACCURACY_100PPM: - *accuracy = 100U; - break; - case NRF_BICR_LFOSC_ACCURACY_75PPM: - *accuracy = 75U; - break; - case NRF_BICR_LFOSC_ACCURACY_50PPM: - *accuracy = 50U; - break; - case NRF_BICR_LFOSC_ACCURACY_30PPM: - *accuracy = 30U; - break; - case NRF_BICR_LFOSC_ACCURACY_20PPM: - *accuracy = 20U; - break; - default: - return -EINVAL; + clock_control_cb_t callback = ((lfclk_data_t *)dev->data)->cb; + void *user_data = ((lfclk_data_t *)dev->data)->user_data; + + ((lfclk_data_t *)dev->data)->cb = NULL; + set_on_state(&((lfclk_data_t *)dev->data)->flags); + DBG(dev, "Clock started"); + + if (callback) { + callback(dev, NULL, user_data); } +} - return 0; +static inline void anomaly_132_workaround(void) +{ +#if (CONFIG_NRF52_ANOMALY_132_DELAY_US - 0) + static bool once; + + if (!once) { + k_busy_wait(CONFIG_NRF52_ANOMALY_132_DELAY_US); + once = true; + } +#endif } -static void clock_evt_handler(nrfs_clock_evt_t const *p_evt, void *context) +static void lfclk_start(void) { - struct lfclk_dev_data *dev_data = context; - int status = 0; + if (IS_ENABLED(CONFIG_NRF52_ANOMALY_132_WORKAROUND)) { + anomaly_132_workaround(); + } + +#if CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH + sys_notify_init_spinwait(&lfsynth_cli.notify); - k_timer_stop(&dev_data->timer); + (void)nrf_clock_control_request(CLOCK_DEVICE_HF, NULL, &lfsynth_cli); +#endif + + nrfx_clock_lfclk_start(); +} - if (p_evt->type == NRFS_CLOCK_EVT_REJECT) { - status = -ENXIO; +static void lfclk_stop(void) +{ + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { + z_nrf_clock_calibration_lfclk_stopped(); } - clock_config_update_end(&dev_data->clk_cfg, status); + nrfx_clock_lfclk_stop(); + +#if CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH + + (void)nrf_clock_control_cancel_or_release(CLOCK_DEVICE_HF, NULL, &lfsynth_cli); +#endif } -static void lfclk_update_timeout_handler(struct k_timer *timer) +static int stop(const struct device *dev, uint32_t ctx) { - struct lfclk_dev_data *dev_data = - CONTAINER_OF(timer, struct lfclk_dev_data, timer); + int err; - clock_config_update_end(&dev_data->clk_cfg, -ETIMEDOUT); + err = set_off_state(&((lfclk_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((lfclk_config_t *)dev->config)->stop(); + + return 0; } -static void lfclk_work_handler(struct k_work *work) +static void blocking_start_callback(const struct device *dev, + clock_control_subsys_t subsys, + void *user_data) { - struct lfclk_dev_data *dev_data = - CONTAINER_OF(work, struct lfclk_dev_data, clk_cfg.work); - uint8_t to_activate_idx; - nrfs_err_t err; + struct k_sem *sem = user_data; - to_activate_idx = clock_config_update_begin(work); + k_sem_give(sem); +} - err = nrfs_clock_lfclk_src_set(clock_options[to_activate_idx].src, - dev_data); - if (err != NRFS_SUCCESS) { - clock_config_update_end(&dev_data->clk_cfg, -EIO); - } else { - k_timer_start(&dev_data->timer, NRFS_CLOCK_TIMEOUT, K_NO_WAIT); +static int async_start(const struct device *dev, clock_control_cb_t cb, void *user_data, + uint32_t ctx) +{ + int err; + + err = set_starting_state(&((lfclk_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; } + + ((lfclk_data_t *)dev->data)->cb = cb; + ((lfclk_data_t *)dev->data)->user_data = user_data; + + ((lfclk_config_t *)dev->config)->start(); + + return 0; } -static int lfclk_resolve_spec_to_idx(const struct device *dev, - const struct nrf_clock_spec *req_spec) +/** @brief Wait for LF clock availability or stability. + * + * If LF clock source is SYNTH or RC then there is no distinction between + * availability and stability. In case of XTAL source clock, system is initially + * starting RC and then seamlessly switches to XTAL. Running RC means clock + * availability and running target source means stability, That is because + * significant difference in startup time (<1ms vs >200ms). + * + * In order to get event/interrupt when RC is ready (allowing CPU sleeping) two + * stage startup sequence is used. Initially, LF source is set to RC and when + * LFSTARTED event is handled it is reconfigured to the target source clock. + * This approach is implemented in nrfx_clock_lfclk driver and utilized here. + * + * @param mode Start mode. + */ +static void lfclk_spinwait(enum nrf_lfclk_start_mode mode) { - struct lfclk_dev_data *dev_data = dev->data; - const struct lfclk_dev_config *dev_config = dev->config; - uint16_t req_accuracy; - - if (req_spec->frequency > dev_config->fixed_frequency) { - LOG_ERR("invalid frequency"); - return -EINVAL; + static const nrf_clock_lfclk_t target_type = + /* For sources XTAL, EXT_LOW_SWING, and EXT_FULL_SWING, + * NRF_CLOCK_LFCLK_XTAL is returned as the type of running clock. + */ + (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL) || + IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING) || + IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING)) + ? NRF_CLOCK_LFCLK_XTAL + : CLOCK_CONTROL_NRF_K32SRC; + nrf_clock_lfclk_t type; + + if ((mode == CLOCK_CONTROL_NRF_LF_START_AVAILABLE) && + (target_type == NRF_CLOCK_LFCLK_XTAL) && + (nrf_clock_lf_srccopy_get(NRF_CLOCK) == CLOCK_CONTROL_NRF_K32SRC)) { + /* If target clock source is using XTAL then due to two-stage + * clock startup sequence, RC might already be running. + * It can be determined by checking current LFCLK source. If it + * is set to the target clock source then it means that RC was + * started. + */ + return; } - req_accuracy = req_spec->accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX - ? dev_data->max_accuracy - : req_spec->accuracy; + bool isr_mode = k_is_in_isr() || k_is_pre_kernel(); + int key = isr_mode ? irq_lock() : 0; + + if (!isr_mode) { + nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK); + } - for (int i = dev_data->clock_options_cnt - 1; i >= 0; --i) { - /* Iterate to a more power hungry and accurate clock source - * If the requested accuracy is higher (lower ppm) than what - * the clock source can provide. - * - * In case of an accuracy of 0 (don't care), do not check accuracy. + while (!(nrfx_clock_lfclk_running_check((void *)&type) + && ((type == target_type) + || (mode == CLOCK_CONTROL_NRF_LF_START_AVAILABLE)))) { + /* Synth source start is almost instant and LFCLKSTARTED may + * happen before calling idle. That would lead to deadlock. */ - if ((req_accuracy != 0 && req_accuracy < clock_options[i].accuracy) || - (req_spec->precision > clock_options[i].precision)) { - continue; + if (!IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH)) { + if (isr_mode || !IS_ENABLED(CONFIG_MULTITHREADING)) { + k_cpu_atomic_idle(key); + } else { + k_msleep(1); + } } - return i; + /* Clock interrupt is locked, LFCLKSTARTED is handled here. */ + if ((target_type == NRF_CLOCK_LFCLK_XTAL) + && (nrf_clock_lf_src_get(NRF_CLOCK) == NRF_CLOCK_LFCLK_RC) + && nrf_clock_event_check(NRF_CLOCK, + NRF_CLOCK_EVENT_LFCLKSTARTED)) { + nrf_clock_event_clear(NRF_CLOCK, + NRF_CLOCK_EVENT_LFCLKSTARTED); + nrf_clock_lf_src_set(NRF_CLOCK, + CLOCK_CONTROL_NRF_K32SRC); + + /* Clear pending interrupt, otherwise new clock event + * would not wake up from idle. + */ + NVIC_ClearPendingIRQ(DT_INST_IRQN(0)); + nrf_clock_task_trigger(NRF_CLOCK, + NRF_CLOCK_TASK_LFCLKSTART); + } } - LOG_ERR("invalid accuracy or precision"); - return -EINVAL; + if (isr_mode) { + irq_unlock(key); + } else { + nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK); + } } -static void lfclk_get_spec_by_idx(const struct device *dev, - uint8_t idx, - struct nrf_clock_spec *spec) +static void clock_event_handler(nrfx_clock_lfclk_evt_type_t event) { - const struct lfclk_dev_config *dev_config = dev->config; + const struct device *dev = CLOCK_DEVICE_LFCLK; - spec->frequency = dev_config->fixed_frequency; - spec->accuracy = clock_options[idx].accuracy; - spec->precision = clock_options[idx].precision; + switch (event) { + case NRFX_CLOCK_LFCLK_EVT_LFCLK_STARTED: + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { + z_nrf_clock_calibration_lfclk_started(); + } + clkstarted_handle(dev); + break; +#if NRF_CLOCK_HAS_CALIBRATION || NRF_LFRC_HAS_CALIBRATION + case NRFX_CLOCK_LFCLK_EVT_CAL_DONE: + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { + z_nrf_clock_calibration_done_handler(); + } else { + /* Should not happen when calibration is disabled. */ + __ASSERT_NO_MSG(false); + } + break; +#endif + default: + __ASSERT_NO_MSG(0); + break; + } } -static struct onoff_manager *lfclk_get_mgr_by_idx(const struct device *dev, uint8_t idx) +static void onoff_started_callback(const struct device *dev, + clock_control_subsys_t sys, + void *user_data) { - struct lfclk_dev_data *dev_data = dev->data; + onoff_notify_fn notify = user_data; - return &dev_data->clk_cfg.onoff[idx].mgr; + notify(&((lfclk_data_t *)dev->data)->mgr, 0); } -static int lfclk_get_startup_time_by_idx(const struct device *dev, - uint8_t idx, - uint32_t *startup_time_us) +static void onoff_start(struct onoff_manager *mgr, onoff_notify_fn notify) { - struct lfclk_dev_data *dev_data = dev->data; - nrfs_clock_src_t src = clock_options[idx].src; - - switch (src) { - case NRFS_CLOCK_SRC_LFCLK_LFLPRC: - *startup_time_us = LFCLK_LFLPRC_STARTUP_TIME_US; - return 0; - - case NRFS_CLOCK_SRC_LFCLK_LFRC: - *startup_time_us = LFCLK_LFRC_STARTUP_TIME_US; - return 0; - - case NRFS_CLOCK_SRC_LFCLK_XO_PIXO: - case NRFS_CLOCK_SRC_LFCLK_XO_PIERCE: - case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE: - case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE: - case NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP: - case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP: - *startup_time_us = dev_data->lfxo_startup_time_us; - return 0; - - case NRFS_CLOCK_SRC_LFCLK_SYNTH: - *startup_time_us = dev_data->hfxo_startup_time_us; - return 0; + int err; - default: - break; + err = async_start(CLOCK_DEVICE_LFCLK, onoff_started_callback, + notify, CTX_ONOFF); + if (err < 0) { + notify(mgr, err); } - - return -EINVAL; } -static struct onoff_manager *lfclk_find_mgr_by_spec(const struct device *dev, - const struct nrf_clock_spec *spec) +static void onoff_stop(struct onoff_manager *mgr, + onoff_notify_fn notify) { - int idx; + int res; - if (!spec) { - return lfclk_get_mgr_by_idx(dev, 0); - } - - idx = lfclk_resolve_spec_to_idx(dev, spec); - return idx < 0 ? NULL : lfclk_get_mgr_by_idx(dev, idx); + res = stop(CLOCK_DEVICE_LFCLK, CTX_ONOFF); + notify(mgr, res); } -static int api_request_lfclk(const struct device *dev, - const struct nrf_clock_spec *spec, - struct onoff_client *cli) +void z_nrf_clock_control_lf_on(enum nrf_lfclk_start_mode start_mode) { - struct onoff_manager *mgr = lfclk_find_mgr_by_spec(dev, spec); + static atomic_t on; + static struct onoff_client cli; + + if (atomic_set(&on, 1) == 0) { + int err; + struct onoff_manager *mgr = &((lfclk_data_t *)CLOCK_DEVICE_LFCLK->data)->mgr; - if (mgr) { - return clock_config_request(mgr, cli); + sys_notify_init_spinwait(&cli.notify); + err = onoff_request(mgr, &cli); + __ASSERT_NO_MSG(err >= 0); } - return -EINVAL; -} + /* In case of simulated board leave immediately. */ + if (IS_ENABLED(CONFIG_SOC_SERIES_BSIM_NRFXX)) { + return; + } -static int api_release_lfclk(const struct device *dev, - const struct nrf_clock_spec *spec) -{ - struct onoff_manager *mgr = lfclk_find_mgr_by_spec(dev, spec); + switch (start_mode) { + case CLOCK_CONTROL_NRF_LF_START_AVAILABLE: + case CLOCK_CONTROL_NRF_LF_START_STABLE: + lfclk_spinwait(start_mode); + break; - if (mgr) { - return onoff_release(mgr); + case CLOCK_CONTROL_NRF_LF_START_NOWAIT: + break; + + default: + __ASSERT_NO_MSG(false); } +} - return -EINVAL; +static int api_start(const struct device *dev, clock_control_subsys_t subsys, clock_control_cb_t cb, + void *user_data) +{ + ARG_UNUSED(subsys); + + return async_start(dev, cb, user_data, CTX_API); } -static int api_cancel_or_release_lfclk(const struct device *dev, - const struct nrf_clock_spec *spec, - struct onoff_client *cli) +static int api_blocking_start(const struct device *dev, + clock_control_subsys_t subsys) { - struct onoff_manager *mgr = lfclk_find_mgr_by_spec(dev, spec); + struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1); + int err; - if (mgr) { - return onoff_cancel_or_release(mgr, cli); + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return -ENOTSUP; } - return -EINVAL; -} + err = api_start(dev, subsys, blocking_start_callback, &sem); + if (err < 0) { + return err; + } + return k_sem_take(&sem, K_MSEC(500)); +} -static int api_resolve(const struct device *dev, - const struct nrf_clock_spec *req_spec, - struct nrf_clock_spec *res_spec) +static int api_stop(const struct device *dev, clock_control_subsys_t subsys) { - int idx; + ARG_UNUSED(subsys); - idx = lfclk_resolve_spec_to_idx(dev, req_spec); - if (idx < 0) { - return -EINVAL; - } + return stop(dev, CTX_API); +} - lfclk_get_spec_by_idx(dev, idx, res_spec); - return 0; +static enum clock_control_status api_get_status(const struct device *dev, + clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return GET_STATUS(((lfclk_data_t *)dev->data)->flags); } -static int api_get_startup_time(const struct device *dev, - const struct nrf_clock_spec *spec, - uint32_t *startup_time_us) +static int api_request(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) { - int idx; + lfclk_data_t *dev_data = dev->data; - idx = lfclk_resolve_spec_to_idx(dev, spec); - if (idx < 0) { - return -EINVAL; - } + ARG_UNUSED(spec); - return lfclk_get_startup_time_by_idx(dev, idx, startup_time_us); + return onoff_request(&dev_data->mgr, cli); } -static int api_get_rate_lfclk(const struct device *dev, - clock_control_subsys_t sys, - uint32_t *rate) +static int api_release(const struct device *dev, + const struct nrf_clock_spec *spec) { - ARG_UNUSED(sys); + lfclk_data_t *dev_data = dev->data; - const struct lfclk_dev_config *dev_config = dev->config; + ARG_UNUSED(spec); - *rate = dev_config->fixed_frequency; - - return 0; + return onoff_release(&dev_data->mgr); } -static int lfclk_init(const struct device *dev) +static int api_cancel_or_release(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) { - struct lfclk_dev_data *dev_data = dev->data; - nrf_bicr_lfosc_mode_t lfosc_mode; - nrfs_err_t res; - - res = nrfs_clock_init(clock_evt_handler); - if (res != NRFS_SUCCESS) { - return -EIO; - } + lfclk_data_t *dev_data = dev->data; - dev_data->clock_options_cnt = LFCLK_DEF_OPTS; + ARG_UNUSED(spec); - lfosc_mode = nrf_bicr_lfosc_mode_get(BICR); + return onoff_cancel_or_release(&dev_data->mgr, cli); +} - if (lfosc_mode == NRF_BICR_LFOSC_MODE_UNCONFIGURED || - lfosc_mode == NRF_BICR_LFOSC_MODE_DISABLED) { - dev_data->max_accuracy = LFCLK_HFXO_ACCURACY; - } else { - int ret; +static int clk_init(const struct device *dev) +{ + int err; + static const struct onoff_transitions transitions = { + .start = onoff_start, + .stop = onoff_stop + }; - ret = lfosc_get_accuracy(&dev_data->max_accuracy); - if (ret < 0) { - LOG_ERR("LFOSC enabled with invalid accuracy"); - return ret; - } + clock_control_nrf_common_connect_irq(); - switch (lfosc_mode) { - case NRF_BICR_LFOSC_MODE_CRYSTAL: - clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; - clock_options[LFCLK_MAX_OPTS - 1].precision = 0; - clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE; - - clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; - clock_options[LFCLK_MAX_OPTS - 2].precision = 1; - clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP; - - dev_data->clock_options_cnt += 2; - break; - case NRF_BICR_LFOSC_MODE_EXTSINE: - clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; - clock_options[LFCLK_MAX_OPTS - 1].precision = 0; - clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE; - - clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; - clock_options[LFCLK_MAX_OPTS - 2].precision = 1; - clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP; - - dev_data->clock_options_cnt += 2; - break; - case NRF_BICR_LFOSC_MODE_EXTSQUARE: - clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; - clock_options[LFCLK_MAX_OPTS - 2].precision = 0; - clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE; - - dev_data->clock_options_cnt += 1; - break; - default: - LOG_ERR("Unexpected LFOSC mode"); - return -EINVAL; - } + if (nrfx_clock_lfclk_init(clock_event_handler) != 0) { + return -EIO; + } - dev_data->lfxo_startup_time_us = nrf_bicr_lfosc_startup_time_ms_get(BICR) - * USEC_PER_MSEC; - if (dev_data->lfxo_startup_time_us == NRF_BICR_LFOSC_STARTUP_TIME_UNCONFIGURED) { - LOG_ERR("BICR LFXO startup time invalid"); - return -ENODEV; - } + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { + z_nrf_clock_calibration_init(); } - dev_data->hfxo_startup_time_us = nrf_bicr_hfxo_startup_time_us_get(BICR); - if (dev_data->hfxo_startup_time_us == NRF_BICR_HFXO_STARTUP_TIME_UNCONFIGURED) { - LOG_ERR("BICR HFXO startup time invalid"); - return -ENODEV; + err = onoff_manager_init(&((lfclk_data_t *)dev->data)->mgr, &transitions); + if (err < 0) { + return err; } - k_timer_init(&dev_data->timer, lfclk_update_timeout_handler, NULL); + ((lfclk_data_t *)dev->data)->flags = CLOCK_CONTROL_STATUS_OFF; - return clock_config_init(&dev_data->clk_cfg, - ARRAY_SIZE(dev_data->clk_cfg.onoff), - lfclk_work_handler); + return 0; } -static DEVICE_API(nrf_clock_control, lfclk_drv_api) = { +CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(clock_control_nrf_lfclk, &nrfx_clock_lfclk_irq_handler); + +static DEVICE_API(nrf_clock_control, clock_control_api) = { .std_api = { - .on = api_nosys_on_off, - .off = api_nosys_on_off, - .get_rate = api_get_rate_lfclk, + .on = api_blocking_start, + .off = api_stop, + .async_on = api_start, + .get_status = api_get_status, }, - .request = api_request_lfclk, - .release = api_release_lfclk, - .cancel_or_release = api_cancel_or_release_lfclk, - .resolve = api_resolve, - .get_startup_time = api_get_startup_time, + .request = api_request, + .release = api_release, + .cancel_or_release = api_cancel_or_release, }; -static struct lfclk_dev_data lfclk_data; +static lfclk_data_t data; + +static const lfclk_config_t config = { + + .start = lfclk_start, + .stop = lfclk_stop, + IF_ENABLED(CONFIG_LOG, (.name = "lfclk",)) -static const struct lfclk_dev_config lfclk_config = { - .fixed_frequency = DT_INST_PROP(0, clock_frequency), }; -DEVICE_DT_INST_DEFINE(0, lfclk_init, NULL, - &lfclk_data, &lfclk_config, - PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, - &lfclk_drv_api); +DEVICE_DT_DEFINE(DT_NODELABEL(lfclk), clk_init, NULL, + &data, &config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &clock_control_api); diff --git a/drivers/clock_control/clock_control_nrfs_lfclk.c b/drivers/clock_control/clock_control_nrfs_lfclk.c new file mode 100644 index 000000000000..02f916788021 --- /dev/null +++ b/drivers/clock_control/clock_control_nrfs_lfclk.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_nrfs_lfclk + +#include "clock_control_nrf2_common.h" +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "multiple instances not supported"); + +#define LFCLK_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo) + +#define LFCLK_LFRC_ACCURACY DT_INST_PROP(0, lfrc_accuracy_ppm) +#define LFCLK_HFXO_ACCURACY DT_PROP(LFCLK_HFXO_NODE, accuracy_ppm) +#define LFCLK_LFLPRC_STARTUP_TIME_US DT_INST_PROP(0, lflprc_startup_time_us) +#define LFCLK_LFRC_STARTUP_TIME_US DT_INST_PROP(0, lfrc_startup_time_us) + +#define LFCLK_MAX_OPTS 4 +#define LFCLK_DEF_OPTS 2 + +#define NRFS_CLOCK_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRFS_LFCLK_CLOCK_TIMEOUT_MS) + +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + +/* Clock options sorted from highest to lowest power consumption. + * - Clock synthesized from a high frequency clock + * - Internal RC oscillator + * - External clock. These are inserted into the list at driver initialization. + * Set to one of the following: + * - XTAL. Low or High precision + * - External sine or square wave + */ +static struct clock_options { + uint16_t accuracy : 15; + uint16_t precision : 1; + nrfs_clock_src_t src; +} clock_options[LFCLK_MAX_OPTS] = { + { + /* NRFS will request FLL16M use HFXO in bypass mode if SYNTH src is used */ + .accuracy = LFCLK_HFXO_ACCURACY, + .precision = 1, + .src = NRFS_CLOCK_SRC_LFCLK_SYNTH, + }, + { + .accuracy = LFCLK_LFRC_ACCURACY, + .precision = 0, + .src = NRFS_CLOCK_SRC_LFCLK_LFRC, + }, + /* Remaining options are populated on lfclk_init */ +}; + +struct lfclk_dev_data { + STRUCT_CLOCK_CONFIG(lfclk, ARRAY_SIZE(clock_options)) clk_cfg; + struct k_timer timer; + uint16_t max_accuracy; + uint8_t clock_options_cnt; + uint32_t hfxo_startup_time_us; + uint32_t lfxo_startup_time_us; +}; + +struct lfclk_dev_config { + uint32_t fixed_frequency; +}; + +static int lfosc_get_accuracy(uint16_t *accuracy) +{ + switch (nrf_bicr_lfosc_accuracy_get(BICR)) { + case NRF_BICR_LFOSC_ACCURACY_500PPM: + *accuracy = 500U; + break; + case NRF_BICR_LFOSC_ACCURACY_250PPM: + *accuracy = 250U; + break; + case NRF_BICR_LFOSC_ACCURACY_150PPM: + *accuracy = 150U; + break; + case NRF_BICR_LFOSC_ACCURACY_100PPM: + *accuracy = 100U; + break; + case NRF_BICR_LFOSC_ACCURACY_75PPM: + *accuracy = 75U; + break; + case NRF_BICR_LFOSC_ACCURACY_50PPM: + *accuracy = 50U; + break; + case NRF_BICR_LFOSC_ACCURACY_30PPM: + *accuracy = 30U; + break; + case NRF_BICR_LFOSC_ACCURACY_20PPM: + *accuracy = 20U; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void clock_evt_handler(nrfs_clock_evt_t const *p_evt, void *context) +{ + struct lfclk_dev_data *dev_data = context; + int status = 0; + + k_timer_stop(&dev_data->timer); + + if (p_evt->type == NRFS_CLOCK_EVT_REJECT) { + status = -ENXIO; + } + + clock_config_update_end(&dev_data->clk_cfg, status); +} + +static void lfclk_update_timeout_handler(struct k_timer *timer) +{ + struct lfclk_dev_data *dev_data = + CONTAINER_OF(timer, struct lfclk_dev_data, timer); + + clock_config_update_end(&dev_data->clk_cfg, -ETIMEDOUT); +} + +static void lfclk_work_handler(struct k_work *work) +{ + struct lfclk_dev_data *dev_data = + CONTAINER_OF(work, struct lfclk_dev_data, clk_cfg.work); + uint8_t to_activate_idx; + nrfs_err_t err; + + to_activate_idx = clock_config_update_begin(work); + + err = nrfs_clock_lfclk_src_set(clock_options[to_activate_idx].src, + dev_data); + if (err != NRFS_SUCCESS) { + clock_config_update_end(&dev_data->clk_cfg, -EIO); + } else { + k_timer_start(&dev_data->timer, NRFS_CLOCK_TIMEOUT, K_NO_WAIT); + } +} + +static int lfclk_resolve_spec_to_idx(const struct device *dev, + const struct nrf_clock_spec *req_spec) +{ + struct lfclk_dev_data *dev_data = dev->data; + const struct lfclk_dev_config *dev_config = dev->config; + uint16_t req_accuracy; + + if (req_spec->frequency > dev_config->fixed_frequency) { + LOG_ERR("invalid frequency"); + return -EINVAL; + } + + req_accuracy = req_spec->accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX + ? dev_data->max_accuracy + : req_spec->accuracy; + + for (int i = dev_data->clock_options_cnt - 1; i >= 0; --i) { + /* Iterate to a more power hungry and accurate clock source + * If the requested accuracy is higher (lower ppm) than what + * the clock source can provide. + * + * In case of an accuracy of 0 (don't care), do not check accuracy. + */ + if ((req_accuracy != 0 && req_accuracy < clock_options[i].accuracy) || + (req_spec->precision > clock_options[i].precision)) { + continue; + } + + return i; + } + + LOG_ERR("invalid accuracy or precision"); + return -EINVAL; +} + +static void lfclk_get_spec_by_idx(const struct device *dev, + uint8_t idx, + struct nrf_clock_spec *spec) +{ + const struct lfclk_dev_config *dev_config = dev->config; + + spec->frequency = dev_config->fixed_frequency; + spec->accuracy = clock_options[idx].accuracy; + spec->precision = clock_options[idx].precision; +} + +static struct onoff_manager *lfclk_get_mgr_by_idx(const struct device *dev, uint8_t idx) +{ + struct lfclk_dev_data *dev_data = dev->data; + + return &dev_data->clk_cfg.onoff[idx].mgr; +} + +static int lfclk_get_startup_time_by_idx(const struct device *dev, + uint8_t idx, + uint32_t *startup_time_us) +{ + struct lfclk_dev_data *dev_data = dev->data; + nrfs_clock_src_t src = clock_options[idx].src; + + switch (src) { + case NRFS_CLOCK_SRC_LFCLK_LFLPRC: + *startup_time_us = LFCLK_LFLPRC_STARTUP_TIME_US; + return 0; + + case NRFS_CLOCK_SRC_LFCLK_LFRC: + *startup_time_us = LFCLK_LFRC_STARTUP_TIME_US; + return 0; + + case NRFS_CLOCK_SRC_LFCLK_XO_PIXO: + case NRFS_CLOCK_SRC_LFCLK_XO_PIERCE: + case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE: + case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE: + case NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP: + case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP: + *startup_time_us = dev_data->lfxo_startup_time_us; + return 0; + + case NRFS_CLOCK_SRC_LFCLK_SYNTH: + *startup_time_us = dev_data->hfxo_startup_time_us; + return 0; + + default: + break; + } + + return -EINVAL; +} + +static struct onoff_manager *lfclk_find_mgr_by_spec(const struct device *dev, + const struct nrf_clock_spec *spec) +{ + int idx; + + if (!spec) { + return lfclk_get_mgr_by_idx(dev, 0); + } + + idx = lfclk_resolve_spec_to_idx(dev, spec); + return idx < 0 ? NULL : lfclk_get_mgr_by_idx(dev, idx); +} + +static int api_request_lfclk(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + struct onoff_manager *mgr = lfclk_find_mgr_by_spec(dev, spec); + + if (mgr) { + return clock_config_request(mgr, cli); + } + + return -EINVAL; +} + +static int api_release_lfclk(const struct device *dev, + const struct nrf_clock_spec *spec) +{ + struct onoff_manager *mgr = lfclk_find_mgr_by_spec(dev, spec); + + if (mgr) { + return onoff_release(mgr); + } + + return -EINVAL; +} + +static int api_cancel_or_release_lfclk(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + struct onoff_manager *mgr = lfclk_find_mgr_by_spec(dev, spec); + + if (mgr) { + return onoff_cancel_or_release(mgr, cli); + } + + return -EINVAL; +} + + +static int api_resolve(const struct device *dev, + const struct nrf_clock_spec *req_spec, + struct nrf_clock_spec *res_spec) +{ + int idx; + + idx = lfclk_resolve_spec_to_idx(dev, req_spec); + if (idx < 0) { + return -EINVAL; + } + + lfclk_get_spec_by_idx(dev, idx, res_spec); + return 0; +} + +static int api_get_startup_time(const struct device *dev, + const struct nrf_clock_spec *spec, + uint32_t *startup_time_us) +{ + int idx; + + idx = lfclk_resolve_spec_to_idx(dev, spec); + if (idx < 0) { + return -EINVAL; + } + + return lfclk_get_startup_time_by_idx(dev, idx, startup_time_us); +} + +static int api_get_rate_lfclk(const struct device *dev, + clock_control_subsys_t sys, + uint32_t *rate) +{ + ARG_UNUSED(sys); + + const struct lfclk_dev_config *dev_config = dev->config; + + *rate = dev_config->fixed_frequency; + + return 0; +} + +static int lfclk_init(const struct device *dev) +{ + struct lfclk_dev_data *dev_data = dev->data; + nrf_bicr_lfosc_mode_t lfosc_mode; + nrfs_err_t res; + + res = nrfs_clock_init(clock_evt_handler); + if (res != NRFS_SUCCESS) { + return -EIO; + } + + dev_data->clock_options_cnt = LFCLK_DEF_OPTS; + + lfosc_mode = nrf_bicr_lfosc_mode_get(BICR); + + if (lfosc_mode == NRF_BICR_LFOSC_MODE_UNCONFIGURED || + lfosc_mode == NRF_BICR_LFOSC_MODE_DISABLED) { + dev_data->max_accuracy = LFCLK_HFXO_ACCURACY; + } else { + int ret; + + ret = lfosc_get_accuracy(&dev_data->max_accuracy); + if (ret < 0) { + LOG_ERR("LFOSC enabled with invalid accuracy"); + return ret; + } + + switch (lfosc_mode) { + case NRF_BICR_LFOSC_MODE_CRYSTAL: + clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 1].precision = 0; + clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE; + + clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 2].precision = 1; + clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP; + + dev_data->clock_options_cnt += 2; + break; + case NRF_BICR_LFOSC_MODE_EXTSINE: + clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 1].precision = 0; + clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE; + + clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 2].precision = 1; + clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP; + + dev_data->clock_options_cnt += 2; + break; + case NRF_BICR_LFOSC_MODE_EXTSQUARE: + clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 2].precision = 0; + clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE; + + dev_data->clock_options_cnt += 1; + break; + default: + LOG_ERR("Unexpected LFOSC mode"); + return -EINVAL; + } + + dev_data->lfxo_startup_time_us = nrf_bicr_lfosc_startup_time_ms_get(BICR) + * USEC_PER_MSEC; + if (dev_data->lfxo_startup_time_us == NRF_BICR_LFOSC_STARTUP_TIME_UNCONFIGURED) { + LOG_ERR("BICR LFXO startup time invalid"); + return -ENODEV; + } + } + + dev_data->hfxo_startup_time_us = nrf_bicr_hfxo_startup_time_us_get(BICR); + if (dev_data->hfxo_startup_time_us == NRF_BICR_HFXO_STARTUP_TIME_UNCONFIGURED) { + LOG_ERR("BICR HFXO startup time invalid"); + return -ENODEV; + } + + k_timer_init(&dev_data->timer, lfclk_update_timeout_handler, NULL); + + return clock_config_init(&dev_data->clk_cfg, + ARRAY_SIZE(dev_data->clk_cfg.onoff), + lfclk_work_handler); +} + +static DEVICE_API(nrf_clock_control, lfclk_drv_api) = { + .std_api = { + .on = api_nosys_on_off, + .off = api_nosys_on_off, + .get_rate = api_get_rate_lfclk, + }, + .request = api_request_lfclk, + .release = api_release_lfclk, + .cancel_or_release = api_cancel_or_release_lfclk, + .resolve = api_resolve, + .get_startup_time = api_get_startup_time, +}; + +static struct lfclk_dev_data lfclk_data; + +static const struct lfclk_dev_config lfclk_config = { + .fixed_frequency = DT_INST_PROP(0, clock_frequency), +}; + +DEVICE_DT_INST_DEFINE(0, lfclk_init, NULL, + &lfclk_data, &lfclk_config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &lfclk_drv_api); diff --git a/drivers/clock_control/nrf_clock_calibration.c b/drivers/clock_control/nrf_clock_calibration.c index fc2ce4162aa4..b6b7d41237b8 100644 --- a/drivers/clock_control/nrf_clock_calibration.c +++ b/drivers/clock_control/nrf_clock_calibration.c @@ -45,7 +45,6 @@ static void cal_lf_callback(struct onoff_manager *mgr, uint32_t state, int res); static struct onoff_client client; -static struct onoff_manager *mgrs; /* Temperature sensor is only needed if * CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_MAX_SKIP > 0, since a value of 0 @@ -67,42 +66,47 @@ static int16_t prev_temperature; /* Previous temperature measurement. */ static void timeout_handler(struct k_timer *timer); static K_TIMER_DEFINE(backoff_timer, timeout_handler, NULL); -static void clk_request(struct onoff_manager *mgr, struct onoff_client *cli, +static void clk_request(struct device *dev, struct onoff_client *cli, onoff_client_callback callback) { int err; sys_notify_init_callback(&cli->notify, callback); - err = onoff_request(mgr, cli); + err = nrf_clock_control_request(dev, NULL, cli); __ASSERT_NO_MSG(err >= 0); } -static void clk_release(struct onoff_manager *mgr) +static void clk_release(struct device *dev) { int err; - err = onoff_release(mgr); + err = nrf_clock_control_release(dev, NULL); __ASSERT_NO_MSG(err >= 0); } static void hf_request(void) { - clk_request(&mgrs[CLOCK_CONTROL_NRF_TYPE_HFCLK], &client, cal_hf_callback); + clk_request(DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))), + &client, cal_hf_callback); } static void lf_request(void) { - clk_request(&mgrs[CLOCK_CONTROL_NRF_TYPE_LFCLK], &client, cal_lf_callback); + clk_request(DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk), &client, cal_lf_callback); } static void hf_release(void) { - clk_release(&mgrs[CLOCK_CONTROL_NRF_TYPE_HFCLK]); + clk_release(DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo)))); } static void lf_release(void) { - clk_release(&mgrs[CLOCK_CONTROL_NRF_TYPE_LFCLK]); + clk_release(DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk)); } static void cal_lf_callback(struct onoff_manager *mgr, @@ -235,9 +239,8 @@ static void measure_temperature(struct k_work *work) } #endif /* USE_TEMP_SENSOR */ -void z_nrf_clock_calibration_init(struct onoff_manager *onoff_mgrs) +void z_nrf_clock_calibration_init(void) { - mgrs = onoff_mgrs; total_cnt = 0; total_skips_cnt = 0; } diff --git a/drivers/clock_control/nrf_clock_calibration.h b/drivers/clock_control/nrf_clock_calibration.h index 8ea6c95bb07d..2c9b12661b61 100644 --- a/drivers/clock_control/nrf_clock_calibration.h +++ b/drivers/clock_control/nrf_clock_calibration.h @@ -14,10 +14,8 @@ extern "C" { /** * @brief Initialize LFCLK RC calibration. - * - * @param mgrs Pointer to array of onoff managers for HF and LF clocks. */ -void z_nrf_clock_calibration_init(struct onoff_manager *mgrs); +void z_nrf_clock_calibration_init(void); /** * @brief Calibration done handler diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index 4410617aa807..0436a9a10efe 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -80,6 +80,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + nrf_mpu: nrf-mpu@40000000 { compatible = "nordic,nrf-mpu"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index 3391c0a70f9f..0521d9a87b4a 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -68,6 +68,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index 7c91bdae2bc3..5e2564885960 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -72,6 +72,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 418d9331b642..e412a3d2d5ec 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -76,6 +76,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index 1dc8271bae7e..612c2dbcb5f5 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -76,6 +76,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index 982461d73e9e..7541c0cdad04 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -72,6 +72,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index 3ff20567c73a..30583cd94f05 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -76,6 +76,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index d161211e42f7..374fb9e5392d 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -72,6 +72,13 @@ status = "okay"; }; + lfclk: lfclk@40000000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x40000000 0x1000>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@40000000 { compatible = "nordic,nrf-power"; reg = <0x40000000 0x1000>; diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index 9c51df186c2f..1f47bc276641 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -75,6 +75,13 @@ hfclk: hfclk@5000 { status = "okay"; }; +lfclk: lfclk@5000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x5000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; +}; + power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index e06b02211935..611451d04ddf 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -69,6 +69,13 @@ status = "okay"; }; + lfclk: lfclk@41005000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x41005000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + power: power@41005000 { compatible = "nordic,nrf-power"; reg = <0x41005000 0x1000>; diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index 66b817599e46..969c0925dc58 100644 --- a/dts/arm/nordic/nrf91_peripherals.dtsi +++ b/dts/arm/nordic/nrf91_peripherals.dtsi @@ -351,6 +351,13 @@ hfclk: hfclk@5000 { status = "okay"; }; +lfclk: lfclk@5000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x5000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; +}; + power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; diff --git a/dts/bindings/clock/nordic,nrf-clock-lfclk.yaml b/dts/bindings/clock/nordic,nrf-clock-lfclk.yaml new file mode 100644 index 000000000000..78dca8e9c7c6 --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-clock-lfclk.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF lfclk clock control node + +compatible: "nordic,nrf-clock-lfclk" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/clock/nordic,nrf-lfclk.yaml b/dts/bindings/clock/nordic,nrf-lfclk.yaml index a0f95d6c9277..b01ee2e699af 100644 --- a/dts/bindings/clock/nordic,nrf-lfclk.yaml +++ b/dts/bindings/clock/nordic,nrf-lfclk.yaml @@ -27,7 +27,7 @@ description: | clock-names = "hfxo", "lfxo"; }; -compatible: "nordic,nrf-lfclk" +compatible: "nordic,nrfs-lfclk" include: fixed-clock.yaml diff --git a/dts/vendor/nordic/nrf54h20.dtsi b/dts/vendor/nordic/nrf54h20.dtsi index 8a468bd846d1..75d6a1162b4e 100644 --- a/dts/vendor/nordic/nrf54h20.dtsi +++ b/dts/vendor/nordic/nrf54h20.dtsi @@ -192,11 +192,10 @@ }; lfclk: lfclk { - compatible = "nordic,nrf-lfclk"; + compatible = "nordic,nrfs-lfclk"; status = "disabled"; #clock-cells = <0>; clock-frequency = <32768>; - status = "okay"; lfrc-accuracy-ppm = <500>; lflprc-accuracy-ppm = <1000>; lfrc-startup-time-us = <200>; /* To be measured */ diff --git a/dts/vendor/nordic/nrf54l_05_10_15.dtsi b/dts/vendor/nordic/nrf54l_05_10_15.dtsi index 5194cfabdda7..6e2ad9a82e89 100644 --- a/dts/vendor/nordic/nrf54l_05_10_15.dtsi +++ b/dts/vendor/nordic/nrf54l_05_10_15.dtsi @@ -646,6 +646,13 @@ status = "disabled"; }; + lfclk: lfclk@10e000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x10e000 0x1000>; + interrupts = <261 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + power: power@10e000 { compatible = "nordic,nrf-power"; reg = <0x10e000 0x1000>; diff --git a/dts/vendor/nordic/nrf54lm20a.dtsi b/dts/vendor/nordic/nrf54lm20a.dtsi index ce8ff6b08e61..953b6bd34634 100644 --- a/dts/vendor/nordic/nrf54lm20a.dtsi +++ b/dts/vendor/nordic/nrf54lm20a.dtsi @@ -798,6 +798,13 @@ status = "disabled"; }; + lfclk: lfclk@10e000 { + compatible = "nordic,nrf-clock-lfclk"; + reg = <0x10e000 0x1000>; + interrupts = <270 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + power: power@10e000 { compatible = "nordic,nrf-power"; reg = <0x10e000 0x1000>; diff --git a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h index 5b48d96aa32e..a4f254cf00b0 100644 --- a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h +++ b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h @@ -7,33 +7,31 @@ #include "device_subsys.h" #include -#ifndef CONFIG_SOC_NRF52832 -static const struct device_subsys_data subsys_data[] = { - /* On nrf52832 LF clock cannot be stopped because it leads - * to RTC COUNTER register reset and that is unexpected by - * system clock which is disrupted and may hang in the test. - */ - { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_LF, - .startup_us = (CLOCK_CONTROL_NRF_K32SRC == - NRF_CLOCK_LFCLK_RC) ? 1000 : 500000 - } -}; -#endif /* !CONFIG_SOC_NRF52832 */ - +#if NRF_CLOCK_HAS_HFCLK static const struct device_subsys_data subsys_data_hfclk[] = { { .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US } }; - +#endif /* NRF_CLOCK_HAS_HFCLK */ +#if NRF_CLOCK_HAS_XO static const struct device_subsys_data subsys_data_xo[] = { { .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US } }; +#endif /* NRF_CLOCK_HAS_XO */ +#if !defined(CONFIG_SOC_NRF52832) +static const struct device_subsys_data subsys_data_lfclk[] = { + { + .subsys = CLOCK_CONTROL_NRF_SUBSYS_LF, + .startup_us = (CLOCK_CONTROL_NRF_K32SRC == + NRF_CLOCK_LFCLK_RC) ? 1000 : 500000 + } +}; +#endif /* !defined(CONFIG_SOC_NRF52832) */ static const struct device_data devices[] = { #if NRF_CLOCK_HAS_HFCLK @@ -51,10 +49,14 @@ static const struct device_data devices[] = { }, #endif /* NRF_CLOCK_HAS_XO */ #if !defined(CONFIG_SOC_NRF52832) + /* On nrf52832 LF clock cannot be stopped because it leads + * to RTC COUNTER register reset and that is unexpected by + * system clock which is disrupted and may hang in the test. + */ { - .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock), - .subsys_data = subsys_data, - .subsys_cnt = ARRAY_SIZE(subsys_data) - } + .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk), + .subsys_data = subsys_data_lfclk, + .subsys_cnt = ARRAY_SIZE(subsys_data_lfclk) + }, #endif /* !defined(CONFIG_SOC_NRF52832) */ }; diff --git a/tests/drivers/clock_control/clock_control_api/src/test_clock_control.c b/tests/drivers/clock_control/clock_control_api/src/test_clock_control.c index 91af56bd3d29..cd243e9325c1 100644 --- a/tests/drivers/clock_control/clock_control_api/src/test_clock_control.c +++ b/tests/drivers/clock_control/clock_control_api/src/test_clock_control.c @@ -33,10 +33,7 @@ static void setup_instance(const struct device *dev, clock_control_subsys_t subs err = clock_control_off(dev, subsys); #if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_clock) if (err == -EPERM) { - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(subsys); - - err = onoff_release(mgr); + err = nrf_clock_control_release(dev, NULL); if (err >= 0) { break; } @@ -45,28 +42,27 @@ static void setup_instance(const struct device *dev, clock_control_subsys_t subs } while (clock_control_get_status(dev, subsys) != CLOCK_CONTROL_STATUS_OFF); - LOG_INF("setup done"); + LOG_INF("setup done: %s", dev->name); } static void tear_down_instance(const struct device *dev, clock_control_subsys_t subsys) { -#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_clock) +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_clock_lfclk) /* Turn on LF clock using onoff service if it is disabled. */ - const struct device *const clk = DEVICE_DT_GET_ONE(nordic_nrf_clock); + const struct device *const clk = DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk); struct onoff_client cli; - struct onoff_manager *mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF); int err; zassert_true(device_is_ready(clk), "Clock dev is not ready"); - if (clock_control_get_status(clk, CLOCK_CONTROL_NRF_SUBSYS_LF) != + if (clock_control_get_status(clk, NULL) != CLOCK_CONTROL_STATUS_OFF) { return; } sys_notify_init_spinwait(&cli.notify); - err = onoff_request(mgr, &cli); + err = nrf_clock_control_request(clk, NULL, &cli); zassert_true(err >= 0, ""); while (sys_notify_fetch_result(&cli.notify, &err) < 0) { diff --git a/tests/drivers/clock_control/nrf_clock_control/src/main.c b/tests/drivers/clock_control/nrf_clock_control/src/main.c index 83fdc98ca193..914c5be46bbf 100644 --- a/tests/drivers/clock_control/nrf_clock_control/src/main.c +++ b/tests/drivers/clock_control/nrf_clock_control/src/main.c @@ -128,7 +128,7 @@ static const struct test_clk_context global_hsfll_test_clk_contexts[] = { }; #endif -#if defined(CONFIG_CLOCK_CONTROL_NRF_LFCLK) +#if defined(CONFIG_CLOCK_CONTROL_NRFS_LFCLK) const struct nrf_clock_spec test_clk_specs_lfclk[] = { { .frequency = 32768, @@ -351,7 +351,7 @@ ZTEST(nrf2_clock_control, test_global_hsfll_control) } #endif -#if defined(CONFIG_CLOCK_CONTROL_NRF_LFCLK) +#if defined(CONFIG_CLOCK_CONTROL_NRFS_LFCLK) ZTEST(nrf2_clock_control, test_lfclk_control) { TC_PRINT("LFCLK test\n"); From a0a6b048208e73170ce096d9f8310480473c30dd Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Mon, 17 Nov 2025 16:01:57 +0100 Subject: [PATCH 5/9] [nrf fromlist] drivers: clock_control: Separated nrf hfclk192m shim from nrf clock shim. Separated clock_control_nrf_hfclk192m shim from clock_control_nrf shim. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig.nrf | 6 + .../clock_control_nrf_hfclk192m.c | 321 ++++++++++++++++++ .../nordic/nrf5340_cpuapp_peripherals.dtsi | 7 + .../clock/nordic,nrf-clock-hfclk192m.yaml | 15 + .../clock_control_api/src/nrf_device_subsys.h | 15 + .../clock_control_api/testcase.yaml | 1 + 7 files changed, 366 insertions(+) create mode 100644 drivers/clock_control/clock_control_nrf_hfclk192m.c create mode 100644 dts/bindings/clock/nordic,nrf-clock-hfclk192m.yaml diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 1fc767aa2fdd..db7880f06fc4 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -63,6 +63,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK clock_control_nrf_hfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO clock_control_nrf_xo.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK192M clock_control_nrf_hfclk192m.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_COMMON clock_control_nrf_common.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X clock_control_bl61x.c) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index 2f970ac5e783..745a2d0709bd 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -344,6 +344,12 @@ config CLOCK_CONTROL_NRF_LFCLK select CLOCK_CONTROL_NRF_COMMON default y +config CLOCK_CONTROL_NRF_HFCLK192M + bool "NRF HFCLK192M driver support" + depends on DT_HAS_NORDIC_NRF_CLOCK_HFCLK192M_ENABLED + select CLOCK_CONTROL_NRF_COMMON + default y + config CLOCK_CONTROL_NRF_AUXPLL bool "nRF Auxiliary PLL driver" default y diff --git a/drivers/clock_control/clock_control_nrf_hfclk192m.c b/drivers/clock_control/clock_control_nrf_hfclk192m.c new file mode 100644 index 000000000000..3742ee368f57 --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_hfclk192m.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2016-2020 Nordic Semiconductor ASA + * Copyright (c) 2016 Vinayak Kariappa Chettimada + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "nrf_clock_calibration.h" +#include "clock_control_nrf_common.h" +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(clock_control_hfclk192m, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define DT_DRV_COMPAT nordic_nrf_clock_hfclk192m + +#define CLOCK_DEVICE_HFCLK192M DEVICE_DT_GET(DT_NODELABEL(hfclk192m)) + +#define CTX_ONOFF BIT(6) +#define CTX_API BIT(7) +#define CTX_MASK (CTX_ONOFF | CTX_API) + +#define STATUS_MASK 0x7 +#define GET_STATUS(flags) (flags & STATUS_MASK) +#define GET_CTX(flags) (flags & CTX_MASK) + +/* Helper logging macros. */ +#ifdef CONFIG_LOG +#define CLOCK_LOG(lvl, dev, ...) \ + LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \ + "hfclk192m" COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__),\ + (), (, GET_ARGS_LESS_N(1, __VA_ARGS__)))) +#else +#define CLOCK_LOG(...) +#endif + +#define ERR(dev, ...) CLOCK_LOG(ERR, dev, __VA_ARGS__) +#define WRN(dev, ...) CLOCK_LOG(WRN, dev, __VA_ARGS__) +#define INF(dev, ...) CLOCK_LOG(INF, dev, __VA_ARGS__) +#define DBG(dev, ...) CLOCK_LOG(DBG, dev, __VA_ARGS__) + +typedef void (*clk_ctrl_func_t)(void); + +typedef struct { + struct onoff_manager mgr; + clock_control_cb_t cb; + void *user_data; + uint32_t flags; +} hfclk192m_data_t; + +typedef struct { + clk_ctrl_func_t start; /* Clock start function */ + clk_ctrl_func_t stop; /* Clock stop function */ +} hfclk192m_config_t; + +static int set_off_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((current_ctx != 0) && (current_ctx != ctx)) { + err = -EPERM; + } else { + *flags = CLOCK_CONTROL_STATUS_OFF; + } + + irq_unlock(key); + + return err; +} + +static int set_starting_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) { + *flags = CLOCK_CONTROL_STATUS_STARTING | ctx; + } else if (current_ctx != ctx) { + err = -EPERM; + } else { + err = -EALREADY; + } + + irq_unlock(key); + + return err; +} + +static void set_on_state(uint32_t *flags) +{ + unsigned int key = irq_lock(); + + *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags); + irq_unlock(key); +} + +static void clkstarted_handle(const struct device *dev) +{ + clock_control_cb_t callback = ((hfclk192m_data_t *)dev->data)->cb; + + ((hfclk192m_data_t *)dev->data)->cb = NULL; + set_on_state(&((hfclk192m_data_t *)dev->data)->flags); + DBG(dev, "Clock started"); + + if (callback) { + callback(dev, NULL, (hfclk192m_data_t *)dev->data)->user_data); + } +} + +static void hfclk192m_start(void) +{ + nrfx_clock_hfclk192m_start(); +} + +static void hfclk192m_stop(void) +{ + nrfx_clock_hfclk192m_stop(); +} + +static int stop(const struct device *dev, uint32_t ctx) +{ + int err; + + err = set_off_state(&((hfclk192m_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((hfclk192m_config_t *)dev->config)->stop(); + + return 0; +} + +static int async_start(const struct device *dev, clock_control_cb_t cb, void *user_data, + uint32_t ctx) +{ + int err; + + err = set_starting_state(&((hfclk192m_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((hfclk192m_data_t *)dev->data)->cb = cb; + ((hfclk192m_data_t *)dev->data)->user_data = user_data; + + ((hfclk192m_config_t *)dev->config)->start(); + + return 0; +} + +static void blocking_start_callback(const struct device *dev, clock_control_subsys_t subsys, + void *user_data) +{ + ARG_UNUSED(subsys); + + struct k_sem *sem = user_data; + + k_sem_give(sem); +} + +static void onoff_stop(struct onoff_manager *mgr, onoff_notify_fn notify) +{ + int res; + + res = stop(CLOCK_DEVICE_HFCLK192M, CTX_ONOFF); + notify(mgr, res); +} + +static void onoff_started_callback(const struct device *dev, clock_control_subsys_t sys, + void *user_data) +{ + ARG_UNUSED(sys); + + onoff_notify_fn notify = user_data; + + notify(&((hfclk192m_data_t *)dev->data)->mgr, 0); +} + +static void onoff_start(struct onoff_manager *mgr, onoff_notify_fn notify) +{ + int err; + + err = async_start(CLOCK_DEVICE_HFCLK192M, onoff_started_callback, notify, CTX_ONOFF); + if (err < 0) { + notify(mgr, err); + } +} + +static void clock_event_handler(void) +{ + const struct device *dev = CLOCK_DEVICE_HFCLK192M; + + clkstarted_handle(dev); +} + +static int api_start(const struct device *dev, clock_control_subsys_t subsys, clock_control_cb_t cb, + void *user_data) +{ + ARG_UNUSED(subsys); + + return async_start(dev, cb, user_data, CTX_API); +} + +static int api_blocking_start(const struct device *dev, clock_control_subsys_t subsys) +{ + struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1); + int err; + + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return -ENOTSUP; + } + + err = api_start(dev, subsys, blocking_start_callback, &sem); + if (err < 0) { + return err; + } + + return k_sem_take(&sem, K_MSEC(500)); +} + +static int api_stop(const struct device *dev, clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return stop(dev, CTX_API); +} + +static enum clock_control_status api_get_status(const struct device *dev, + clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return GET_STATUS(((hfclk192m_data_t *)dev->data)->flags); +} + +static int api_request(const struct device *dev, const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + hfclk192m_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_request(&dev_data->mgr, cli); +} + +static int api_release(const struct device *dev, const struct nrf_clock_spec *spec) +{ + hfclk192m_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_release(&dev_data->mgr); +} + +static int api_cancel_or_release(const struct device *dev, const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + hfclk192m_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_cancel_or_release(&dev_data->mgr, cli); +} + +static int clk_init(const struct device *dev) +{ + int err; + static const struct onoff_transitions transitions = {.start = onoff_start, + .stop = onoff_stop}; + + clock_control_nrf_common_connect_irq(); + + if (nrfx_clock_hfclk192m_init(clock_event_handler) != 0) { + return -EIO; + } + + err = onoff_manager_init(&((hfclk192m_data_t *)dev->data)->mgr, &transitions); + if (err < 0) { + return err; + } + + ((hfclk192m_data_t *)dev->data)->flags = CLOCK_CONTROL_STATUS_OFF; + + return 0; +} + +CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(clock_control_nrf_hfclk192m, + &nrfx_clock_hfclk192m_irq_handler); + +static DEVICE_API(nrf_clock_control, clock_control_api) = { + .std_api = { + .on = api_blocking_start, + .off = api_stop, + .async_on = api_start, + .get_status = api_get_status, + }, + .request = api_request, + .release = api_release, + .cancel_or_release = api_cancel_or_release, +}; + +static hfclk192m_data_t data; + +static const hfclk192m_config_t config = { + .start = hfclk192m_start, + .stop = hfclk192m_stop, +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(hfclk192m), clk_init, NULL, &data, &config, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_api); diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index 1f47bc276641..1cb15d053e50 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -82,6 +82,13 @@ lfclk: lfclk@5000 { status = "okay"; }; +hfclk192m: hfclk192m@5000 { + compatible = "nordic,nrf-clock-hfclk192m"; + reg = <0x5000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; +}; + power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; diff --git a/dts/bindings/clock/nordic,nrf-clock-hfclk192m.yaml b/dts/bindings/clock/nordic,nrf-clock-hfclk192m.yaml new file mode 100644 index 000000000000..beba070cdee5 --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-clock-hfclk192m.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF hfclk192m clock control node + +compatible: "nordic,nrf-clock-hfclk192m" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h index a4f254cf00b0..29ec39598c0e 100644 --- a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h +++ b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h @@ -32,6 +32,14 @@ static const struct device_subsys_data subsys_data_lfclk[] = { } }; #endif /* !defined(CONFIG_SOC_NRF52832) */ +#if NRF_CLOCK_HAS_HFCLK192M +static const struct device_subsys_data subsys_data_hfclk192m[] = { + { + .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF192M, + .startup_us = 5 + } +}; +#endif /* NRF_CLOCK_HAS_HFCLK192M */ static const struct device_data devices[] = { #if NRF_CLOCK_HAS_HFCLK @@ -59,4 +67,11 @@ static const struct device_data devices[] = { .subsys_cnt = ARRAY_SIZE(subsys_data_lfclk) }, #endif /* !defined(CONFIG_SOC_NRF52832) */ +#if NRF_CLOCK_HAS_HFCLK192M + { + .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_hfclk192m), + .subsys_data = subsys_data_hfclk192m, + .subsys_cnt = ARRAY_SIZE(subsys_data_hfclk192m) + }, +#endif /* NRF_CLOCK_HAS_HFCLK192M */ }; diff --git a/tests/drivers/clock_control/clock_control_api/testcase.yaml b/tests/drivers/clock_control/clock_control_api/testcase.yaml index d3c2669641fc..9935de194582 100644 --- a/tests/drivers/clock_control/clock_control_api/testcase.yaml +++ b/tests/drivers/clock_control/clock_control_api/testcase.yaml @@ -21,6 +21,7 @@ tests: - nrf51dk/nrf51822 - nrf52dk/nrf52832 - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp - nrf9160dk/nrf9160 - nrf54l15dk/nrf54l15/cpuapp - nrf54lm20dk/nrf54lm20a/cpuapp From 10559afc417847731407eb0d10e4d347c4734b65 Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Mon, 17 Nov 2025 16:01:57 +0100 Subject: [PATCH 6/9] [nrf fromlist] drivers: clock_control: Separated nrf xo24m shim from nrf clock shim. Separated clock_control_nrf_xo24m shim from clock_control_nrf shim. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- .../nrf54lm20bsim_nrf54lm20a_cpuapp.dts | 4 + .../nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi | 4 + drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig.nrf | 6 + .../clock_control/clock_control_nrf_xo24m.c | 332 ++++++++++++++++++ .../clock/nordic,nrf-clock-xo24m.yaml | 15 + dts/vendor/nordic/nrf54lm20a.dtsi | 7 + .../clock_control_api/src/nrf_device_subsys.h | 15 + 8 files changed, 384 insertions(+) create mode 100644 drivers/clock_control/clock_control_nrf_xo24m.c create mode 100644 dts/bindings/clock/nordic,nrf-clock-xo24m.yaml diff --git a/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts b/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts index 19efa0cdbfec..0c1cb31e55a8 100644 --- a/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts +++ b/boards/native/nrf_bsim/nrf54lm20bsim_nrf54lm20a_cpuapp.dts @@ -150,3 +150,7 @@ &lfclk { status = "okay"; }; + +&xo24m { + status = "okay"; +}; diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi index 99877b8aa85c..5985ea8e4064 100644 --- a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi +++ b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi @@ -138,6 +138,10 @@ status = "okay"; }; +&xo24m { + status = "okay"; +}; + &ieee802154 { status = "okay"; }; diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index db7880f06fc4..3dfd7325621c 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -64,6 +64,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO clock_control_nrf_xo.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK192M clock_control_nrf_hfclk192m.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO24M clock_control_nrf_xo24m.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_COMMON clock_control_nrf_common.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X clock_control_bl61x.c) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index 745a2d0709bd..7dfc798f30a8 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -350,6 +350,12 @@ config CLOCK_CONTROL_NRF_HFCLK192M select CLOCK_CONTROL_NRF_COMMON default y +config CLOCK_CONTROL_NRF_XO24M + bool "NRF XO242M driver support" + depends on DT_HAS_NORDIC_NRF_CLOCK_XO24M_ENABLED + select CLOCK_CONTROL_NRF_COMMON + default y + config CLOCK_CONTROL_NRF_AUXPLL bool "nRF Auxiliary PLL driver" default y diff --git a/drivers/clock_control/clock_control_nrf_xo24m.c b/drivers/clock_control/clock_control_nrf_xo24m.c new file mode 100644 index 000000000000..879315d0c442 --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_xo24m.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2016-2025 Nordic Semiconductor ASA + * Copyright (c) 2016 Vinayak Kariappa Chettimada + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "clock_control_nrf_common.h" +#include +#include +#include +#include + +LOG_MODULE_REGISTER(clock_control_xo24m, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define DT_DRV_COMPAT nordic_nrf_clock_xo24m + +#define CLOCK_DEVICE_XO24M DEVICE_DT_GET(DT_NODELABEL(xo24m)) + +#define CTX_ONOFF BIT(6) +#define CTX_API BIT(7) +#define CTX_MASK (CTX_ONOFF | CTX_API) + +#define STATUS_MASK 0x7 +#define GET_STATUS(flags) (flags & STATUS_MASK) +#define GET_CTX(flags) (flags & CTX_MASK) + +/* Helper logging macros which prepends subsys name to the log. */ +#ifdef CONFIG_LOG +#define CLOCK_LOG(lvl, dev, ...) \ + LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \ + "xo24m" \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__),\ + (), (, GET_ARGS_LESS_N(1, __VA_ARGS__)))) +#else +#define CLOCK_LOG(...) +#endif + +#define ERR(dev, ...) CLOCK_LOG(ERR, dev, __VA_ARGS__) +#define WRN(dev, ...) CLOCK_LOG(WRN, dev, __VA_ARGS__) +#define INF(dev, ...) CLOCK_LOG(INF, dev, __VA_ARGS__) +#define DBG(dev, ...) CLOCK_LOG(DBG, dev, __VA_ARGS__) + +typedef void (*clk_ctrl_func_t)(void); + +typedef struct { + struct onoff_manager mgr; + clock_control_cb_t cb; + void *user_data; + uint32_t flags; +} xo24m_data_t; + +typedef struct { + clk_ctrl_func_t start; /* Clock start function */ + clk_ctrl_func_t stop; /* Clock stop function */ +} xo24m_config_t; + +static int set_off_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((current_ctx != 0) && (current_ctx != ctx)) { + err = -EPERM; + } else { + *flags = CLOCK_CONTROL_STATUS_OFF; + } + + irq_unlock(key); + + return err; +} + +static int set_starting_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) { + *flags = CLOCK_CONTROL_STATUS_STARTING | ctx; + } else if (current_ctx != ctx) { + err = -EPERM; + } else { + err = -EALREADY; + } + + irq_unlock(key); + + return err; +} + +static void set_on_state(uint32_t *flags) +{ + unsigned int key = irq_lock(); + + *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags); + irq_unlock(key); +} + +static void clkstarted_handle(const struct device *dev) +{ + clock_control_cb_t callback = ((xo24m_data_t *)dev->data)->cb; + void *user_data = ((xo24m_data_t *)dev->data)->user_data; + + ((xo24m_data_t *)dev->data)->cb = NULL; + set_on_state(&((xo24m_data_t *)dev->data)->flags); + DBG(dev, "Clock started"); + + if (callback) { + callback(dev, NULL, user_data); + } +} + +static void xo24m_start(void) +{ + nrfx_clock_xo24m_start(); +} + +static void xo24m_stop(void) +{ + nrfx_clock_xo24m_stop(); +} + +static int stop(const struct device *dev, uint32_t ctx) +{ + int err; + + err = set_off_state(&((xo24m_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((xo24m_config_t *)dev->config)->stop(); + + return 0; +} + +static int async_start(const struct device *dev, clock_control_cb_t cb, void *user_data, + uint32_t ctx) +{ + int err; + + err = set_starting_state(&((xo24m_data_t *)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((xo24m_data_t *)dev->data)->cb = cb; + ((xo24m_data_t *)dev->data)->user_data = user_data; + + ((xo24m_config_t *)dev->config)->start(); + + return 0; +} + +static void blocking_start_callback(const struct device *dev, + clock_control_subsys_t subsys, + void *user_data) +{ + struct k_sem *sem = user_data; + + k_sem_give(sem); +} + +static void onoff_stop(struct onoff_manager *mgr, + onoff_notify_fn notify) +{ + int res; + + res = stop(CLOCK_DEVICE_XO24M, CTX_ONOFF); + notify(mgr, res); +} + +static void onoff_started_callback(const struct device *dev, + clock_control_subsys_t sys, + void *user_data) +{ + ARG_UNUSED(sys); + + onoff_notify_fn notify = user_data; + + notify(&((xo24m_data_t *)dev->data)->mgr, 0); +} + +static void onoff_start(struct onoff_manager *mgr, + onoff_notify_fn notify) +{ + int err; + + err = async_start(CLOCK_DEVICE_XO24M, onoff_started_callback, notify, CTX_ONOFF); + if (err < 0) { + notify(mgr, err); + } +} + +static void clock_event_handler(void) +{ + const struct device *dev = CLOCK_DEVICE_XO24M; + + clkstarted_handle(dev); +} + +static int api_start(const struct device *dev, clock_control_subsys_t subsys, + clock_control_cb_t cb, void *user_data) +{ + ARG_UNUSED(subsys); + + return async_start(dev, cb, user_data, CTX_API); +} + +static int api_blocking_start(const struct device *dev, + clock_control_subsys_t subsys) +{ + struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1); + int err; + + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return -ENOTSUP; + } + + err = api_start(dev, subsys, blocking_start_callback, &sem); + if (err < 0) { + return err; + } + + return k_sem_take(&sem, K_MSEC(500)); +} + +static int api_stop(const struct device *dev, clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return stop(dev, CTX_API); +} + +static enum clock_control_status api_get_status(const struct device *dev, + clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return GET_STATUS(((xo24m_data_t *)dev->data)->flags); +} + +static int api_request(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + xo24m_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_request(&dev_data->mgr, cli); +} + +static int api_release(const struct device *dev, + const struct nrf_clock_spec *spec) +{ + xo24m_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_release(&dev_data->mgr); +} + +static int api_cancel_or_release(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + xo24m_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_cancel_or_release(&dev_data->mgr, cli); +} + +static int clk_init(const struct device *dev) +{ + int err; + static const struct onoff_transitions transitions = { + .start = onoff_start, + .stop = onoff_stop + }; + + clock_control_nrf_common_connect_irq(); + + if (nrfx_clock_xo24m_init(clock_event_handler) != 0) { + return -EIO; + } + + err = onoff_manager_init(&((xo24m_data_t *)dev->data)->mgr, + &transitions); + if (err < 0) { + return err; + } + + ((xo24m_data_t *)dev->data)->flags = CLOCK_CONTROL_STATUS_OFF; + + return 0; +} + +CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(clock_control_nrf_xo24m, + &nrfx_clock_xo24m_irq_handler); + +static DEVICE_API(nrf_clock_control, clock_control_api) = { + .std_api = { + .on = api_blocking_start, + .off = api_stop, + .async_on = api_start, + .get_status = api_get_status, + }, + .request = api_request, + .release = api_release, + .cancel_or_release = api_cancel_or_release, +}; + +static xo24m_data_t data; + +static const xo24m_config_t config = { + .start = xo24m_start, + .stop = xo24m_stop, +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(xo24m), clk_init, NULL, + &data, &config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &clock_control_api); diff --git a/dts/bindings/clock/nordic,nrf-clock-xo24m.yaml b/dts/bindings/clock/nordic,nrf-clock-xo24m.yaml new file mode 100644 index 000000000000..ff520a95907a --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-clock-xo24m.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF xo24m clock control node + +compatible: "nordic,nrf-clock-xo24m" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/vendor/nordic/nrf54lm20a.dtsi b/dts/vendor/nordic/nrf54lm20a.dtsi index 953b6bd34634..31b4e683ede2 100644 --- a/dts/vendor/nordic/nrf54lm20a.dtsi +++ b/dts/vendor/nordic/nrf54lm20a.dtsi @@ -805,6 +805,13 @@ status = "disabled"; }; + xo24m: xo24m@10e000 { + compatible = "nordic,nrf-clock-xo24m"; + reg = <0x10e000 0x1000>; + interrupts = <270 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + power: power@10e000 { compatible = "nordic,nrf-power"; reg = <0x10e000 0x1000>; diff --git a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h index 29ec39598c0e..c9cc3d7020b0 100644 --- a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h +++ b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h @@ -40,6 +40,14 @@ static const struct device_subsys_data subsys_data_hfclk192m[] = { } }; #endif /* NRF_CLOCK_HAS_HFCLK192M */ +#if NRF_CLOCK_HAS_XO24M +static const struct device_subsys_data subsys_data_xo24m[] = { + { + .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF24M, + .startup_us = 5 + } +}; +#endif /* NRF_CLOCK_HAS_XO24M */ static const struct device_data devices[] = { #if NRF_CLOCK_HAS_HFCLK @@ -74,4 +82,11 @@ static const struct device_data devices[] = { .subsys_cnt = ARRAY_SIZE(subsys_data_hfclk192m) }, #endif /* NRF_CLOCK_HAS_HFCLK192M */ +#if NRF_CLOCK_HAS_XO24M + { + .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_xo24m), + .subsys_data = subsys_data_xo24m, + .subsys_cnt = ARRAY_SIZE(subsys_data_xo24m) + }, +#endif /* NRF_CLOCK_HAS_XO24M */ }; From 5f010e51c2e090a0df1b08ba8a9891e74ec8cab4 Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Mon, 17 Nov 2025 16:01:57 +0100 Subject: [PATCH 7/9] [nrf fromlist] drivers: clock_control: Separated nrf hfclkaudio shim from nrf clock shim. Separated clock_control_nrf_hfclkaudio shim from clock_control_nrf shim. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- drivers/audio/dmic_nrfx_pdm.c | 9 +- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig.nrf | 6 + .../clock_control_nrf_hfclkaudio.c | 356 ++++++++++++++++++ drivers/i2s/i2s_nrfx.c | 6 +- .../nordic/nrf5340_cpuapp_peripherals.dtsi | 7 + dts/arm/nordic/nrf5340_cpunet.dtsi | 7 + dts/bindings/audio/nordic,nrf-pdm.yaml | 2 +- .../clock/nordic,nrf-clock-hfclkaudio.yaml | 23 ++ dts/bindings/clock/nordic,nrf-clock.yaml | 8 - dts/bindings/i2s/nordic,nrf-i2s.yaml | 2 +- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 2 +- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 2 +- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 2 +- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 2 +- .../clock_control_api/src/nrf_device_subsys.h | 15 + .../nrf5340dk_nrf5340_cpuapp_aclk.overlay | 2 +- .../nrf5340dk_nrf5340_cpuapp_aclk.overlay | 2 +- 18 files changed, 431 insertions(+), 23 deletions(-) create mode 100644 drivers/clock_control/clock_control_nrf_hfclkaudio.c create mode 100644 dts/bindings/clock/nordic,nrf-clock-hfclkaudio.yaml diff --git a/drivers/audio/dmic_nrfx_pdm.c b/drivers/audio/dmic_nrfx_pdm.c index 4afba3d6168f..7edee8320327 100644 --- a/drivers/audio/dmic_nrfx_pdm.c +++ b/drivers/audio/dmic_nrfx_pdm.c @@ -32,8 +32,9 @@ BUILD_ASSERT((DMIC_NRFX_AUDIO_CLOCK_FREQ == NRF_AUXPLL_FREQ_DIV_AUDIO_48K) || #define DMIC_NRFX_CLOCK_FREQ MHZ(32) #else #define DMIC_NRFX_CLOCK_FREQ MHZ(32) -#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(DT_NODELABEL(aclk), clock_frequency, \ - DT_PROP_OR(DT_NODELABEL(clock), hfclkaudio_frequency, 0)) +#define DMIC_NRFX_AUDIO_CLOCK_FREQ \ + DT_PROP_OR(DT_NODELABEL(aclk), clock_frequency, \ + DT_PROP_OR(DT_NODELABEL(hfclkaudio), hfclkaudio_frequency, 0)) #endif struct dmic_nrfx_pdm_drv_data { @@ -537,13 +538,13 @@ static const struct _dmic_ops dmic_ops = { BUILD_ASSERT(PDM_CLK_SRC(inst) != ACLK || NRF_PDM_HAS_SELECTABLE_CLOCK, \ "Clock source ACLK is not available."); \ BUILD_ASSERT(PDM_CLK_SRC(inst) != ACLK || \ - DT_NODE_HAS_PROP(DT_NODELABEL(clock), hfclkaudio_frequency) || \ + DT_NODE_HAS_PROP(DT_NODELABEL(hfclkaudio), hfclkaudio_frequency) || \ DT_NODE_HAS_PROP(DT_NODELABEL(aclk), clock_frequency) || \ DT_NODE_HAS_PROP(NODE_AUDIOPLL, frequency) || \ DT_NODE_HAS_PROP(NODE_AUDIO_AUXPLL, nordic_frequency), \ "Clock source ACLK requires one following defined frequency " \ "properties: " \ - "hfclkaudio-frequency in the nordic,nrf-clock node, " \ + "hfclkaudio-frequency in the nordic,nrf-clock-hfclkaudio node, " \ "clock-frequency in the aclk node, " \ "frequency in the audiopll node, " \ "nordic-frequency in the audio_auxpll node"); \ diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 3dfd7325621c..acdcd3b532e4 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -64,6 +64,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO clock_control_nrf_xo.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HFCLK192M clock_control_nrf_hfclk192m.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO24M clock_control_nrf_hfclkaudio.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_XO24M clock_control_nrf_xo24m.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_COMMON clock_control_nrf_common.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index 7dfc798f30a8..192f6505b2f0 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -350,6 +350,12 @@ config CLOCK_CONTROL_NRF_HFCLK192M select CLOCK_CONTROL_NRF_COMMON default y +config CLOCK_CONTROL_NRF_HFCLKAUDIO + bool "NRF HFCLKAUDIO driver support" + depends on DT_HAS_NORDIC_NRF_CLOCK_HFCLKAUDIO_ENABLED + select CLOCK_CONTROL_NRF_COMMON + default y + config CLOCK_CONTROL_NRF_XO24M bool "NRF XO242M driver support" depends on DT_HAS_NORDIC_NRF_CLOCK_XO24M_ENABLED diff --git a/drivers/clock_control/clock_control_nrf_hfclkaudio.c b/drivers/clock_control/clock_control_nrf_hfclkaudio.c new file mode 100644 index 000000000000..72bb0b9f9d05 --- /dev/null +++ b/drivers/clock_control/clock_control_nrf_hfclkaudio.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2016-2020 Nordic Semiconductor ASA + * Copyright (c) 2016 Vinayak Kariappa Chettimada + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "clock_control_nrf_common.h" +#include +#include +#include +#include + +LOG_MODULE_REGISTER(clock_control_hfclkaudio, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define DT_DRV_COMPAT nordic_nrf_clock_hfclkaudio + +#define CLOCK_DEVICE_HFCLKAUDIO DEVICE_DT_GET(DT_NODELABEL(hfclkaudio)) + +#define CTX_ONOFF BIT(6) +#define CTX_API BIT(7) +#define CTX_MASK (CTX_ONOFF | CTX_API) + +#define STATUS_MASK 0x7 +#define GET_STATUS(flags) (flags & STATUS_MASK) +#define GET_CTX(flags) (flags & CTX_MASK) + +/* Helper logging macros which prepends subsys name to the log. */ +#ifdef CONFIG_LOG +#define CLOCK_LOG(lvl, dev, ...) \ + LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \ + "hfclkaudio" \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__),\ + (), (, GET_ARGS_LESS_N(1, __VA_ARGS__)))) +#else +#define CLOCK_LOG(...) +#endif + +#define ERR(dev, ...) CLOCK_LOG(ERR, dev, __VA_ARGS__) +#define WRN(dev, ...) CLOCK_LOG(WRN, dev, __VA_ARGS__) +#define INF(dev, ...) CLOCK_LOG(INF, dev, __VA_ARGS__) +#define DBG(dev, ...) CLOCK_LOG(DBG, dev, __VA_ARGS__) + +typedef void (*clk_ctrl_func_t)(void); + +typedef struct { + struct onoff_manager mgr; + clock_control_cb_t cb; + void *user_data; + uint32_t flags; +} hfclkaudio_data_t; + +typedef struct { + clk_ctrl_func_t start; /* Clock start function */ + clk_ctrl_func_t stop; /* Clock stop function */ +} hfclkaudio_config_t; + +static int set_off_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((current_ctx != 0) && (current_ctx != ctx)) { + err = -EPERM; + } else { + *flags = CLOCK_CONTROL_STATUS_OFF; + } + + irq_unlock(key); + + return err; +} + +static int set_starting_state(uint32_t *flags, uint32_t ctx) +{ + int err = 0; + unsigned int key = irq_lock(); + uint32_t current_ctx = GET_CTX(*flags); + + if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) { + *flags = CLOCK_CONTROL_STATUS_STARTING | ctx; + } else if (current_ctx != ctx) { + err = -EPERM; + } else { + err = -EALREADY; + } + + irq_unlock(key); + + return err; +} + +static void set_on_state(uint32_t *flags) +{ + unsigned int key = irq_lock(); + + *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags); + irq_unlock(key); +} + +static void clkstarted_handle(const struct device *dev, + enum clock_control_nrf_type type) +{ + clock_control_cb_t callback = ((hfclkaudio_data_t)dev->data)->cb; + + ((hfclkaudio_data_t)dev->data)->cb = NULL; + set_on_state(&((hfclkaudio_data_t)dev->data)->flags); + DBG(dev, "Clock started"); + + if (callback) { + callback(dev, NULL, ((hfclkaudio_data_t)dev->data)->user_data); + } +} + +static void hfclkaudio_start(void) +{ + nrfx_clock_hfclkaudio_start(); +} + +static void hfclkaudio_stop(void) +{ + nrfx_clock_hfclkaudio_stop(); +} + +static int stop(const struct device *dev, uint32_t ctx) +{ + int err; + + err = set_off_state(&((hfclkaudio_data_t)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((hfclkaudio_config_t)dev->config)->stop(); + + return 0; +} + +static int async_start(const struct device *dev, clock_control_cb_t cb, void *user_data, + uint32_t ctx) +{ + int err; + + err = set_starting_state(&((hfclkaudio_data_t)dev->data)->flags, ctx); + if (err < 0) { + return err; + } + + ((hfclkaudio_data_t)dev->data)->cb = cb; + ((hfclkaudio_data_t)dev->data)->user_data = user_data; + + ((hfclkaudio_config_t)dev->config)->start(); + + return 0; +} + +static void blocking_start_callback(const struct device *dev, + clock_control_subsys_t subsys, + void *user_data) +{ + ARG_UNUSED(subsys); + ARG_UNUSED(dev); + + struct k_sem *sem = user_data; + + k_sem_give(sem); +} + +static void onoff_stop(struct onoff_manager *mgr, + onoff_notify_fn notify) +{ + int res; + + res = stop(CLOCK_DEVICE_HFCLKAUDIO, CTX_ONOFF); + notify(mgr, res); +} + +static void onoff_started_callback(const struct device *dev, + clock_control_subsys_t sys, + void *user_data) +{ + ARG_UNUSED(sys); + + onoff_notify_fn notify = user_data; + + notify(&((hfclkaudio_data_t)dev->data)->mgr, 0); +} + +static void onoff_start(struct onoff_manager *mgr, + onoff_notify_fn notify) +{ + int err; + + err = async_start(CLOCK_DEVICE_HFCLKAUDIO, onoff_started_callback, notify, CTX_ONOFF); + if (err < 0) { + notify(mgr, err); + } +} + +static void clock_event_handler(void) +{ + const struct device *dev = CLOCK_DEVICE_HFCLKAUDIO; + + clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLKAUDIO); +} + +static void hfclkaudio_init(void) +{ +#if DT_NODE_HAS_PROP(DT_NODELABEL(hfclkaudio), hfclkaudio_frequency) + const uint32_t frequency = + DT_PROP(DT_NODELABEL(hfclkaudio), hfclkaudio_frequency); + /* As specified in the nRF5340 PS: + * + * FREQ_VALUE = 2^16 * ((12 * f_out / 32M) - 4) + */ + const uint32_t freq_value = + (uint32_t)((384ULL * frequency) / 15625) - 262144; + +#if NRF_CLOCK_HAS_HFCLKAUDIO + nrf_clock_hfclkaudio_config_set(NRF_CLOCK, freq_value); +#else +#error "hfclkaudio-frequency specified but HFCLKAUDIO clock is not present." +#endif /* NRF_CLOCK_HAS_HFCLKAUDIO */ +#endif +} + +static int api_start(const struct device *dev, clock_control_subsys_t subsys, + clock_control_cb_t cb, void *user_data) +{ + ARG_UNUSED(subsys); + + return async_start(dev, cb, user_data, CTX_API); +} + +static int api_blocking_start(const struct device *dev, + clock_control_subsys_t subsys) +{ + struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1); + int err; + + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return -ENOTSUP; + } + + err = api_start(dev, subsys, blocking_start_callback, &sem); + if (err < 0) { + return err; + } + + return k_sem_take(&sem, K_MSEC(500)); +} + +static int api_stop(const struct device *dev, clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return stop(dev, CTX_API); +} + +static enum clock_control_status api_get_status(const struct device *dev, + clock_control_subsys_t subsys) +{ + ARG_UNUSED(subsys); + + return GET_STATUS(((hfclkaudio_data_t)dev->data)->flags); +} + +static int api_request(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + hfclkaudio_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_request(&dev_data->mgr, cli); +} + +static int api_release(const struct device *dev, + const struct nrf_clock_spec *spec) +{ + hfclkaudio_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_release(&dev_data->mgr); +} + +static int api_cancel_or_release(const struct device *dev, + const struct nrf_clock_spec *spec, + struct onoff_client *cli) +{ + hfclkaudio_data_t *dev_data = dev->data; + + ARG_UNUSED(spec); + + return onoff_cancel_or_release(&dev_data->mgr, cli); +} + +static int clk_init(const struct device *dev) +{ + int err; + static const struct onoff_transitions transitions = { + .start = onoff_start, + .stop = onoff_stop + }; + + clock_control_nrf_common_connect_irq(); + + if (nrfx_clock_hfclkaudio_init(clock_event_handler) != 0) { + return -EIO; + } + + hfclkaudio_init(); + + err = onoff_manager_init(&((hfclkaudio_data_t)dev->data)->mgr, &transitions); + if (err < 0) { + return err; + } + + ((hfclkaudio_data_t)dev->data)->flags = CLOCK_CONTROL_STATUS_OFF; + + return 0; +} + +CLOCK_CONTROL_NRF_IRQ_HANDLERS_ITERABLE(clock_control_nrf_hfclkaudio, + &nrfx_clock_hfclkaudio_irq_handler); + +static DEVICE_API(nrf_clock_control, clock_control_api) = { + .std_api = { + .on = api_blocking_start, + .off = api_stop, + .async_on = api_start, + .get_status = api_get_status, + }, + .request = api_request, + .release = api_release, + .cancel_or_release = api_cancel_or_release, +}; + +static hfclkaudio_data_t data; + +static const hfclkaudio_config_t config = { + .start = hfclkaudio_start, + .stop = hfclkaudio_stop, +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(hfclkaudio), clk_init, NULL, + &data, &config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &clock_control_api); diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index 1e8433988dac..e15d56d31ed7 100644 --- a/drivers/i2s/i2s_nrfx.c +++ b/drivers/i2s/i2s_nrfx.c @@ -75,7 +75,7 @@ static void find_suitable_clock(const struct i2s_nrfx_drv_cfg *drv_cfg, * prevent compilation errors when the property is not defined * (this expression will be eventually optimized away then). */ - ? DT_PROP_OR(DT_NODELABEL(clock), hfclkaudio_frequency, 0) + ? DT_PROP_OR(DT_NODELABEL(hfclkaudio), hfclkaudio_frequency, 0) : 32*1000*1000UL, .transfer_rate = i2s_cfg->frame_clk_freq, .swidth = config->sample_width, @@ -866,9 +866,9 @@ static DEVICE_API(i2s, i2s_nrf_drv_api) = { (NRF_I2S_HAS_CLKCONFIG && NRF_CLOCK_HAS_HFCLKAUDIO), \ "Clock source ACLK is not available."); \ BUILD_ASSERT(I2S_CLK_SRC(inst) != ACLK || \ - DT_NODE_HAS_PROP(DT_NODELABEL(clock), hfclkaudio_frequency), \ + DT_NODE_HAS_PROP(DT_NODELABEL(hfclkaudio), hfclkaudio_frequency), \ "Clock source ACLK requires the hfclkaudio-frequency " \ - "property to be defined in the nordic,nrf-clock node."); \ + "property to be defined in the nordic,nrf-clock-hfclkaudio node."); \ DEVICE_DT_INST_DEFINE(inst, i2s_nrfx_init##inst, NULL, &i2s_nrfx_data##inst, \ &i2s_nrfx_cfg##inst, POST_KERNEL, CONFIG_I2S_INIT_PRIORITY, \ &i2s_nrf_drv_api); diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index 1cb15d053e50..2723fe424793 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -89,6 +89,13 @@ hfclk192m: hfclk192m@5000 { status = "okay"; }; +hfclkaudio: hfclkaudio@5000 { + compatible = "nordic,nrf-clock-hfclkaudio"; + reg = <0x5000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; +}; + power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index 611451d04ddf..ab3ded645f6c 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -69,6 +69,13 @@ status = "okay"; }; + hfclkaudio: hfclkaudio@41005000 { + compatible = "nordic,nrf-clock-hfclkaudio"; + reg = <0x41005000 0x1000>; + interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; + status = "okay"; + }; + lfclk: lfclk@41005000 { compatible = "nordic,nrf-clock-lfclk"; reg = <0x41005000 0x1000>; diff --git a/dts/bindings/audio/nordic,nrf-pdm.yaml b/dts/bindings/audio/nordic,nrf-pdm.yaml index e700a0205358..62474d7f28c9 100644 --- a/dts/bindings/audio/nordic,nrf-pdm.yaml +++ b/dts/bindings/audio/nordic,nrf-pdm.yaml @@ -31,7 +31,7 @@ properties: (HFXO) for better clock accuracy and jitter performance - "ACLK": Audio PLL clock with configurable frequency (frequency for this clock must be set via the "hfclkaudio-frequency" property - in the "nordic,nrf-clock" node); this clock source requires the use of HFXO + in the "nordic,nrf-clock-hfclkaudio" node); this clock source requires the use of HFXO enum: - "PCLK32M" - "PCLK32M_HFXO" diff --git a/dts/bindings/clock/nordic,nrf-clock-hfclkaudio.yaml b/dts/bindings/clock/nordic,nrf-clock-hfclkaudio.yaml new file mode 100644 index 000000000000..4c0822a13b7d --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-clock-hfclkaudio.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF hfclkaudio clock control node + +compatible: "nordic,nrf-clock-hfclkaudio" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + hfclkaudio-frequency: + type: int + description: | + Frequency of the HFCLKAUDIO clock in Hz. Adjustable with 3.3 ppm + resolution in two frequency bands - 11.176 MHz to 11.402 MHz, and + 12.165 MHz to 12.411 MHz (refer to the relevant Product Specification). + The HFCLKAUDIO clock is only available in the nRF53 Series SoCs. diff --git a/dts/bindings/clock/nordic,nrf-clock.yaml b/dts/bindings/clock/nordic,nrf-clock.yaml index 22cde89bcfb1..855b450aa712 100644 --- a/dts/bindings/clock/nordic,nrf-clock.yaml +++ b/dts/bindings/clock/nordic,nrf-clock.yaml @@ -13,11 +13,3 @@ properties: interrupts: required: true - - hfclkaudio-frequency: - type: int - description: | - Frequency of the HFCLKAUDIO clock in Hz. Adjustable with 3.3 ppm - resolution in two frequency bands - 11.176 MHz to 11.402 MHz, and - 12.165 MHz to 12.411 MHz (refer to the relevant Product Specification). - The HFCLKAUDIO clock is only available in the nRF53 Series SoCs. diff --git a/dts/bindings/i2s/nordic,nrf-i2s.yaml b/dts/bindings/i2s/nordic,nrf-i2s.yaml index 90fa9f76c5af..801d2f9bae7d 100644 --- a/dts/bindings/i2s/nordic,nrf-i2s.yaml +++ b/dts/bindings/i2s/nordic,nrf-i2s.yaml @@ -32,7 +32,7 @@ properties: (HFXO) for better clock accuracy and jitter performance - "ACLK": Audio PLL clock with configurable frequency (frequency for this clock must be set via the "hfclkaudio-frequency" property - in the "nordic,nrf-clock" node); this clock source is only available + in the "nordic,nrf-clock-hfclkaudio" node); this clock source is only available in the nRF53 Series SoCs and it requires the use of HFXO enum: - "PCLK32M" diff --git a/samples/drivers/audio/dmic/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/drivers/audio/dmic/boards/nrf5340dk_nrf5340_cpuapp.overlay index 769ef276ebcf..2fe96be45e6a 100644 --- a/samples/drivers/audio/dmic/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/samples/drivers/audio/dmic/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -&clock { +&hfclkaudio { hfclkaudio-frequency = <12288000>; }; diff --git a/samples/drivers/i2s/echo/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/drivers/i2s/echo/boards/nrf5340dk_nrf5340_cpuapp.overlay index c68c24a56115..f556f8a0b7f6 100644 --- a/samples/drivers/i2s/echo/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/samples/drivers/i2s/echo/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -42,7 +42,7 @@ }; }; -&clock { +&hfclkaudio { hfclkaudio-frequency = <11289600>; }; diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay index 47205e2ed61e..c6529d5452e2 100644 --- a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -16,7 +16,7 @@ }; }; -&clock { +&hfclkaudio { hfclkaudio-frequency = <12288000>; }; diff --git a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay index 4aeb41953569..3bb31c8aa250 100644 --- a/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/samples/subsys/usb/uac2_implicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -17,7 +17,7 @@ }; }; -&clock { +&hfclkaudio { hfclkaudio-frequency = <12288000>; }; diff --git a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h index c9cc3d7020b0..5960d8f5e06c 100644 --- a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h +++ b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h @@ -40,6 +40,14 @@ static const struct device_subsys_data subsys_data_hfclk192m[] = { } }; #endif /* NRF_CLOCK_HAS_HFCLK192M */ +#if NRF_CLOCK_HAS_HFCLKAUDIO +static const struct device_subsys_data subsys_data_hfclkaudio[] = { + { + .subsys = CLOCK_CONTROL_NRF_SUBSYS_HFAUDIO, + .startup_us = 30 + } +}; +#endif /* NRF_CLOCK_HAS_HFCLKAUDIO */ #if NRF_CLOCK_HAS_XO24M static const struct device_subsys_data subsys_data_xo24m[] = { { @@ -82,6 +90,13 @@ static const struct device_data devices[] = { .subsys_cnt = ARRAY_SIZE(subsys_data_hfclk192m) }, #endif /* NRF_CLOCK_HAS_HFCLK192M */ +#if NRF_CLOCK_HAS_HFCLKAUDIO + { + .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_hfclkaudio), + .subsys_data = subsys_data_hfclkaudio, + .subsys_cnt = ARRAY_SIZE(subsys_data_hfclkaudio) + }, +#endif /* NRF_CLOCK_HAS_HFCLKAUDIO */ #if NRF_CLOCK_HAS_XO24M { .dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_xo24m), diff --git a/tests/drivers/i2s/i2s_additional/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay b/tests/drivers/i2s/i2s_additional/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay index e262ca8d8a87..012a138a972d 100644 --- a/tests/drivers/i2s/i2s_additional/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay +++ b/tests/drivers/i2s/i2s_additional/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay @@ -1,6 +1,6 @@ /* Drive i2s peripheral from ACLK. */ -&clock { +&hfclkaudio { hfclkaudio-frequency = <11289600>; }; diff --git a/tests/drivers/i2s/i2s_speed/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay b/tests/drivers/i2s/i2s_speed/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay index e262ca8d8a87..012a138a972d 100644 --- a/tests/drivers/i2s/i2s_speed/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay +++ b/tests/drivers/i2s/i2s_speed/boards/nrf5340dk_nrf5340_cpuapp_aclk.overlay @@ -1,6 +1,6 @@ /* Drive i2s peripheral from ACLK. */ -&clock { +&hfclkaudio { hfclkaudio-frequency = <11289600>; }; From d0e8579de438a70345d334482c345cabf8fd7d2f Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Mon, 17 Nov 2025 16:01:57 +0100 Subject: [PATCH 8/9] [nrf fromlist] treewide: Replace onoff manager api with nrf_clock_control api. Replaced onoff manager api with nrf_clock_control api wherever z_nrf_clock_control_get_onoff was used. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- drivers/audio/dmic_nrfx_pdm.c | 18 +++++------ drivers/i2s/i2s_nrf_tdm.c | 26 ++-------------- drivers/i2s/i2s_nrfx.c | 20 ++++++------ drivers/led_strip/ws2812_gpio.c | 10 +++--- drivers/sensor/nordic/temp/temp_nrf5.c | 16 +++++----- drivers/usb/device/usb_dc_nrfx.c | 19 ++++++------ drivers/usb/udc/udc_dwc2_vendor_quirks.h | 8 ++--- drivers/usb/udc/udc_nrf.c | 19 ++++++------ .../drivers/clock_control/nrf_clock_control.h | 8 ----- .../platform/nrf_802154_clock_zephyr.c | 20 ++++++------ .../controller/ll_sw/nordic/lll/lll_clock.c | 31 +++++++------------ .../src/test_nrf_clock_calibration.c | 26 +++++++--------- .../clock_control/nrf_onoff_and_bt/src/main.c | 12 ++++--- .../onoff/src/test_clock_control_onoff.c | 24 ++++++-------- 14 files changed, 109 insertions(+), 148 deletions(-) diff --git a/drivers/audio/dmic_nrfx_pdm.c b/drivers/audio/dmic_nrfx_pdm.c index 7edee8320327..345141021a67 100644 --- a/drivers/audio/dmic_nrfx_pdm.c +++ b/drivers/audio/dmic_nrfx_pdm.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -42,7 +42,7 @@ struct dmic_nrfx_pdm_drv_data { #if CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL || DT_NODE_HAS_STATUS_OKAY(NODE_AUDIO_AUXPLL) const struct device *audiopll_dev; #elif CONFIG_CLOCK_CONTROL_NRF - struct onoff_manager *clk_mgr; + const struct device *clk_dev; #endif struct onoff_client clk_cli; struct k_mem_slab *mem_slab; @@ -87,7 +87,7 @@ static int request_clock(struct dmic_nrfx_pdm_drv_data *drv_data) #if CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL || DT_NODE_HAS_STATUS_OKAY(NODE_AUDIO_AUXPLL) return nrf_clock_control_request(drv_data->audiopll_dev, NULL, &drv_data->clk_cli); #elif CONFIG_CLOCK_CONTROL_NRF - return onoff_request(drv_data->clk_mgr, &drv_data->clk_cli); + return nrf_clock_control_request(drv_data->clk_dev, NULL, &drv_data->clk_cli); #else return -ENOTSUP; #endif @@ -101,7 +101,7 @@ static int release_clock(struct dmic_nrfx_pdm_drv_data *drv_data) #if CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL || DT_NODE_HAS_STATUS_OKAY(NODE_AUDIO_AUXPLL) return nrf_clock_control_release(drv_data->audiopll_dev, NULL); #elif CONFIG_CLOCK_CONTROL_NRF - return onoff_release(drv_data->clk_mgr); + return nrf_clock_control_release(drv_data->clk_dev, NULL); #else return -ENOTSUP; #endif @@ -468,21 +468,21 @@ static void init_clock_manager(const struct device *dev) struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; drv_data->audiopll_dev = DEVICE_DT_GET(NODE_AUDIO_AUXPLL); #elif CONFIG_CLOCK_CONTROL_NRF - clock_control_subsys_t subsys; struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; #if NRF_CLOCK_HAS_HFCLKAUDIO const struct dmic_nrfx_pdm_drv_cfg *drv_cfg = dev->config; if (drv_cfg->clk_src == ACLK) { - subsys = CLOCK_CONTROL_NRF_SUBSYS_HFAUDIO; + drv_data->clk_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_hfclkaudio); } else #endif { - subsys = CLOCK_CONTROL_NRF_SUBSYS_HF; + drv_data->clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); } - drv_data->clk_mgr = z_nrf_clock_control_get_onoff(subsys); - __ASSERT_NO_MSG(drv_data->clk_mgr != NULL); + __ASSERT_NO_MSG(drv_data->clk_dev != NULL); #elif CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; diff --git a/drivers/i2s/i2s_nrf_tdm.c b/drivers/i2s/i2s_nrf_tdm.c index 45e5b3d18049..fa9a5ae35477 100644 --- a/drivers/i2s/i2s_nrf_tdm.c +++ b/drivers/i2s/i2s_nrf_tdm.c @@ -106,9 +106,6 @@ struct tdm_drv_cfg { }; struct tdm_drv_data { -#if CONFIG_CLOCK_CONTROL_NRF - struct onoff_manager *clk_mgr; -#endif struct onoff_client clk_cli; struct stream_cfg tx; struct k_msgq tx_queue; @@ -129,9 +126,7 @@ struct tdm_drv_data { static int audio_clock_request(struct tdm_drv_data *drv_data) { -#if DT_NODE_HAS_STATUS_OKAY(NODE_ACLK) && CONFIG_CLOCK_CONTROL_NRF - return onoff_request(drv_data->clk_mgr, &drv_data->clk_cli); -#elif DT_NODE_HAS_STATUS_OKAY(NODE_ACLK) && CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL +#if DT_NODE_HAS_STATUS_OKAY(NODE_ACLK) && CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL return nrf_clock_control_request(audiopll, &aclk_spec, &drv_data->clk_cli); #else (void)drv_data; @@ -142,9 +137,7 @@ static int audio_clock_request(struct tdm_drv_data *drv_data) static int audio_clock_release(struct tdm_drv_data *drv_data) { -#if DT_NODE_HAS_STATUS_OKAY(NODE_ACLK) && CONFIG_CLOCK_CONTROL_NRF - return onoff_release(drv_data->clk_mgr); -#elif DT_NODE_HAS_STATUS_OKAY(NODE_ACLK) && CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL +#if DT_NODE_HAS_STATUS_OKAY(NODE_ACLK) && CONFIG_CLOCK_CONTROL_NRFS_AUDIOPLL (void)drv_data; return nrf_clock_control_release(audiopll, &aclk_spec); @@ -1110,20 +1103,6 @@ static void data_handler(const struct device *dev, const tdm_buffers_t *released } } -static void clock_manager_init(const struct device *dev) -{ -#if CONFIG_CLOCK_CONTROL_NRF && NRF_CLOCK_HAS_HFCLKAUDIO - clock_control_subsys_t subsys; - struct tdm_drv_data *drv_data = dev->data; - - subsys = CLOCK_CONTROL_NRF_SUBSYS_HFAUDIO; - drv_data->clk_mgr = z_nrf_clock_control_get_onoff(subsys); - __ASSERT_NO_MSG(drv_data->clk_mgr != NULL); -#else - (void)dev; -#endif -} - static int data_init(const struct device *dev) { struct tdm_drv_data *drv_data = dev->data; @@ -1190,7 +1169,6 @@ static DEVICE_API(i2s, tdm_nrf_drv_api) = { sizeof(struct tdm_buf), ARRAY_SIZE(tx_msgs##idx)); \ k_msgq_init(&tdm_nrf_data##idx.rx_queue, (char *)rx_msgs##idx, \ sizeof(struct tdm_buf), ARRAY_SIZE(rx_msgs##idx)); \ - clock_manager_init(dev); \ return 0; \ } \ BUILD_ASSERT((TDM_SCK_CLK_SRC(idx) != ACLK && TDM_MCK_CLK_SRC(idx) != ACLK) || \ diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index e15d56d31ed7..a15cf9281773 100644 --- a/drivers/i2s/i2s_nrfx.c +++ b/drivers/i2s/i2s_nrfx.c @@ -29,7 +29,7 @@ struct i2s_buf { }; struct i2s_nrfx_drv_data { - struct onoff_manager *clk_mgr; + struct device *clk_dev; struct onoff_client clk_cli; struct stream_cfg tx; struct k_msgq tx_queue; @@ -184,7 +184,7 @@ static void data_handler(const struct device *dev, } nrfx_i2s_uninit(&drv_data->i2s); if (drv_data->request_clock) { - (void)onoff_release(drv_data->clk_mgr); + (void)nrf_clock_control_release(drv_data->clk_dev, NULL); } } @@ -602,7 +602,7 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data) nrfx_i2s_uninit(&drv_data->i2s); if (drv_data->request_clock) { - (void)onoff_release(drv_data->clk_mgr); + (void)nrf_clock_control_release(drv_data->clk_dev, NULL); } if (initial_buffers.p_tx_buffer) { @@ -630,7 +630,7 @@ static void clock_started_callback(struct onoff_manager *mgr, */ if (drv_data->state == I2S_STATE_READY) { nrfx_i2s_uninit(&drv_data->i2s); - (void)onoff_release(drv_data->clk_mgr); + (void)nrf_clock_control_release(drv_data->clk_dev, NULL); } else { (void)start_transfer(drv_data); } @@ -667,7 +667,7 @@ static int trigger_start(const struct device *dev) if (drv_data->request_clock) { sys_notify_init_callback(&drv_data->clk_cli.notify, clock_started_callback); - ret = onoff_request(drv_data->clk_mgr, &drv_data->clk_cli); + ret = nrf_clock_control_request(drv_data->clk_dev, NULL, &drv_data->clk_cli); if (ret < 0) { nrfx_i2s_uninit(&drv_data->i2s); drv_data->state = I2S_STATE_READY; @@ -796,21 +796,21 @@ static int i2s_nrfx_trigger(const struct device *dev, static void init_clock_manager(const struct device *dev) { struct i2s_nrfx_drv_data *drv_data = dev->data; - clock_control_subsys_t subsys; #if NRF_CLOCK_HAS_HFCLKAUDIO const struct i2s_nrfx_drv_cfg *drv_cfg = dev->config; if (drv_cfg->clk_src == ACLK) { - subsys = CLOCK_CONTROL_NRF_SUBSYS_HFAUDIO; + drv_data->clk_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_hfclkaudio); } else #endif { - subsys = CLOCK_CONTROL_NRF_SUBSYS_HF; + drv_data->clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); } - drv_data->clk_mgr = z_nrf_clock_control_get_onoff(subsys); - __ASSERT_NO_MSG(drv_data->clk_mgr != NULL); + __ASSERT_NO_MSG(drv_data->clk_dev != NULL); } static DEVICE_API(i2s, i2s_nrf_drv_api) = { diff --git a/drivers/led_strip/ws2812_gpio.c b/drivers/led_strip/ws2812_gpio.c index 739aa0f8af62..7c0c11ed06f4 100644 --- a/drivers/led_strip/ws2812_gpio.c +++ b/drivers/led_strip/ws2812_gpio.c @@ -78,14 +78,16 @@ static int send_buf(const struct device *dev, uint8_t *buf, size_t len) const struct ws2812_gpio_cfg *config = dev->config; volatile uint32_t *base = (uint32_t *)&NRF_GPIO->OUTSET; const uint32_t val = BIT(config->gpio.pin); - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); + struct device *clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); struct onoff_client cli; unsigned int key; int rc; sys_notify_init_spinwait(&cli.notify); - rc = onoff_request(mgr, &cli); + + rc = nrf_clock_control_request(clk_dev, NULL, &cli); if (rc < 0) { return rc; } @@ -122,7 +124,7 @@ static int send_buf(const struct device *dev, uint8_t *buf, size_t len) irq_unlock(key); - rc = onoff_release(mgr); + rc = nrf_clock_control_release(drv_data->clk_dev, NULL); /* Returns non-negative value on success. Cap to 0 as API states. */ rc = MIN(rc, 0); diff --git a/drivers/sensor/nordic/temp/temp_nrf5.c b/drivers/sensor/nordic/temp/temp_nrf5.c index b549459d02cd..641b519d1c90 100644 --- a/drivers/sensor/nordic/temp/temp_nrf5.c +++ b/drivers/sensor/nordic/temp/temp_nrf5.c @@ -27,7 +27,7 @@ struct temp_nrf5_data { struct k_sem device_sync_sem; struct k_mutex mutex; int32_t sample; - struct onoff_manager *clk_mgr; + struct device *clk_dev; }; static void hfclk_on_callback(struct onoff_manager *mgr, @@ -46,7 +46,7 @@ static int temp_nrf5_sample_fetch(const struct device *dev, int r; /* Error if before sensor initialized */ - if (data->clk_mgr == NULL) { + if (clock_control_get_status(data->clk_dev, NULL) != CLOCK_CONTROL_STATUS_ON) { return -EAGAIN; } @@ -57,12 +57,12 @@ static int temp_nrf5_sample_fetch(const struct device *dev, k_mutex_lock(&data->mutex, K_FOREVER); sys_notify_init_callback(&cli.notify, hfclk_on_callback); - r = onoff_request(data->clk_mgr, &cli); + r = nrf_clock_control_request(data->clk_dev, NULL, &cli); __ASSERT_NO_MSG(r >= 0); k_sem_take(&data->device_sync_sem, K_FOREVER); - r = onoff_release(data->clk_mgr); + r = nrf_clock_control_release(data->clk_dev, NULL); __ASSERT_NO_MSG(r >= 0); data->sample = nrf_temp_result_get(NRF_TEMP); @@ -113,10 +113,10 @@ static int temp_nrf5_init(const struct device *dev) { struct temp_nrf5_data *data = dev->data; - /* A null clk_mgr indicates sensor has not been initialized */ - data->clk_mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); - __ASSERT_NO_MSG(data->clk_mgr); + data->clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); + __ASSERT_NO_MSG(data->clk_dev); k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT); k_mutex_init(&data->mutex); diff --git a/drivers/usb/device/usb_dc_nrfx.c b/drivers/usb/device/usb_dc_nrfx.c index c8bbfd40ada8..6a0a51992856 100644 --- a/drivers/usb/device/usb_dc_nrfx.c +++ b/drivers/usb/device/usb_dc_nrfx.c @@ -226,7 +226,7 @@ static uint8_t ep_isoout_bufs[CFG_EP_ISOOUT_CNT][ISO_EP_BUF_MAX_SZ] * @param status_cb Status callback for USB DC notifications * @param setup Setup packet for Control requests * @param hfxo_cli Onoff client used to control HFXO - * @param hfxo_mgr Pointer to onoff manager associated with HFXO. + * @param hfxo_dev Pointer to HFXO device. * @param clk_requested Flag used to protect against double stop. * @param attached USBD Attached flag * @param ready USBD Ready flag set after pullup @@ -239,7 +239,7 @@ struct nrf_usbd_ctx { usb_dc_status_callback status_cb; struct usb_setup_packet setup; struct onoff_client hfxo_cli; - struct onoff_manager *hfxo_mgr; + struct device *hfxo_dev; atomic_t clk_requested; bool attached; @@ -534,7 +534,7 @@ static void usb_dc_power_event_handler(nrfx_power_usb_evt_t event) static int hfxo_stop(struct nrf_usbd_ctx *ctx) { if (atomic_cas(&ctx->clk_requested, 1, 0)) { - return onoff_cancel_or_release(ctx->hfxo_mgr, &ctx->hfxo_cli); + return nrf_clock_control_cancel_or_release(ctx->hfxo_dev, NULL, &ctx->hfxo_cli); } return 0; @@ -545,7 +545,7 @@ static int hfxo_start(struct nrf_usbd_ctx *ctx) if (atomic_cas(&ctx->clk_requested, 0, 1)) { sys_notify_init_spinwait(&ctx->hfxo_cli.notify); - return onoff_request(ctx->hfxo_mgr, &ctx->hfxo_cli); + return nrf_clock_control_request(ctx->hfxo_dev, NULL, &ctx->hfxo_cli); } return 0; @@ -1276,11 +1276,12 @@ int usb_dc_attach(void) } k_mutex_init(&ctx->drv_lock); - ctx->hfxo_mgr = - z_nrf_clock_control_get_onoff( - COND_CODE_1(NRF_CLOCK_HAS_HFCLK192M, - (CLOCK_CONTROL_NRF_SUBSYS_HF192M), - (CLOCK_CONTROL_NRF_SUBSYS_HF))); + + ctx->hfxo_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK192M), + (nordic_nrf_clock_hfclk192m), + (COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))))); IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), nrfx_isr, nrf_usbd_common_irq_handler, 0); diff --git a/drivers/usb/udc/udc_dwc2_vendor_quirks.h b/drivers/usb/udc/udc_dwc2_vendor_quirks.h index 4fdcea5ff4fe..096ef92ecc6b 100644 --- a/drivers/usb/udc/udc_dwc2_vendor_quirks.h +++ b/drivers/usb/udc/udc_dwc2_vendor_quirks.h @@ -333,7 +333,7 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE) static K_EVENT_DEFINE(usbhs_events); #define USBHS_VBUS_READY BIT(0) -static struct onoff_manager *pclk24m_mgr; +static struct device *pclk24m_dev; static struct onoff_client pclk24m_cli; static void vregusb_isr(const void *arg) @@ -369,7 +369,7 @@ static inline int usbhs_init_vreg_and_clock(const struct device *dev) } irq_enable(VREGUSB_IRQn); - pclk24m_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF24M); + pclk24m_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_xo24m); return 0; } @@ -390,7 +390,7 @@ static inline int usbhs_enable_core(const struct device *dev) /* Request PCLK24M using clock control driver */ sys_notify_init_spinwait(&pclk24m_cli.notify); - err = onoff_request(pclk24m_mgr, &pclk24m_cli); + err = nrf_clock_control_request(pclk24m_dev, NULL, &pclk24m_cli); if (err < 0) { LOG_ERR("Failed to start PCLK24M %d", err); return err; @@ -436,7 +436,7 @@ static inline int usbhs_disable_core(const struct device *dev) wrapper->ENABLE = 0UL; /* Release PCLK24M using clock control driver */ - err = onoff_cancel_or_release(pclk24m_mgr, &pclk24m_cli); + err = nrf_clock_control_cancel_or_release(pclk24m_dev, NULL, &pclk24m_cli); if (err < 0) { LOG_ERR("Failed to stop PCLK24M %d", err); return err; diff --git a/drivers/usb/udc/udc_nrf.c b/drivers/usb/udc/udc_nrf.c index 7b18862fa596..21e691540e16 100644 --- a/drivers/usb/udc/udc_nrf.c +++ b/drivers/usb/udc/udc_nrf.c @@ -1160,12 +1160,11 @@ static void nrf_usbd_legacy_transfer_out_drop(nrf_usbd_common_ep_t ep) } struct udc_nrf_config { - clock_control_subsys_t clock; + const struct device *clk_dev; nrfx_power_config_t pwr; nrfx_power_usbevt_config_t evt; }; -static struct onoff_manager *hfxo_mgr; static struct onoff_client hfxo_cli; static void udc_event_xfer_in_next(const struct device *dev, const uint8_t ep) @@ -1702,6 +1701,7 @@ static int udc_nrf_host_wakeup(const struct device *dev) static int udc_nrf_enable(const struct device *dev) { + const struct udc_nrf_config *cfg = dev->config; unsigned int key; int ret; @@ -1718,7 +1718,7 @@ static int udc_nrf_enable(const struct device *dev) } sys_notify_init_spinwait(&hfxo_cli.notify); - ret = onoff_request(hfxo_mgr, &hfxo_cli); + ret = nrf_clock_control_request(cfg->clk_dev, NULL, &hfxo_cli); if (ret < 0) { LOG_ERR("Failed to start HFXO %d", ret); return ret; @@ -1734,6 +1734,7 @@ static int udc_nrf_enable(const struct device *dev) static int udc_nrf_disable(const struct device *dev) { + const struct udc_nrf_config *cfg = dev->config; int ret; nrf_usbd_legacy_disable(); @@ -1748,7 +1749,7 @@ static int udc_nrf_disable(const struct device *dev) return -EIO; } - ret = onoff_cancel_or_release(hfxo_mgr, &hfxo_cli); + ret = nrf_clock_control_cancel_or_release(cfg->clk_dev, NULL, &hfxo_cli); if (ret < 0) { LOG_ERR("Failed to stop HFXO %d", ret); return ret; @@ -1761,8 +1762,6 @@ static int udc_nrf_init(const struct device *dev) { const struct udc_nrf_config *cfg = dev->config; - hfxo_mgr = z_nrf_clock_control_get_onoff(cfg->clock); - #ifdef CONFIG_HAS_HW_NRF_USBREG /* Use CLOCK/POWER priority for compatibility with other series where * USB events are handled by CLOCK interrupt handler. @@ -1873,9 +1872,11 @@ static void udc_nrf_unlock(const struct device *dev) } static const struct udc_nrf_config udc_nrf_cfg = { - .clock = COND_CODE_1(NRF_CLOCK_HAS_HFCLK192M, - (CLOCK_CONTROL_NRF_SUBSYS_HF192M), - (CLOCK_CONTROL_NRF_SUBSYS_HF)), + .clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK192M), + (nordic_nrf_clock_hfclk192m), + (COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))))); .pwr = { .dcdcen = (DT_PROP(DT_INST(0, nordic_nrf5x_regulator), regulator_initial_mode) == NRF5X_REG_MODE_DCDC), diff --git a/include/zephyr/drivers/clock_control/nrf_clock_control.h b/include/zephyr/drivers/clock_control/nrf_clock_control.h index 37fc4a1f1a85..f328ef378f1e 100644 --- a/include/zephyr/drivers/clock_control/nrf_clock_control.h +++ b/include/zephyr/drivers/clock_control/nrf_clock_control.h @@ -128,14 +128,6 @@ int z_nrf_clock_calibration_skips_count(void); */ bool z_nrf_clock_calibration_is_in_progress(void); -/** @brief Get onoff service for given clock subsystem. - * - * @param sys Subsystem. - * - * @return Service handler or NULL. - */ -struct onoff_manager *z_nrf_clock_control_get_onoff(clock_control_subsys_t sys); - /** @brief Permanently enable low frequency clock. * * Low frequency clock is usually enabled during application lifetime because diff --git a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c index 8593ff7269b4..b4bb84f325c7 100644 --- a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c +++ b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c @@ -50,11 +50,6 @@ static void hfclk_on_callback(struct onoff_manager *mgr, #if defined(CONFIG_CLOCK_CONTROL_NRF) void nrf_802154_clock_hfclk_start(void) { - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); - - __ASSERT_NO_MSG(mgr != NULL); - sys_notify_init_callback(&hfclk_cli.notify, hfclk_on_callback); /* @@ -65,19 +60,24 @@ void nrf_802154_clock_hfclk_start(void) nrf_sys_event_request_global_constlat(); } - int ret = onoff_request(mgr, &hfclk_cli); + struct device *clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); + + int ret = nrf_clock_control_request(clk_dev, NULL, &hfclk_cli); + __ASSERT_NO_MSG(ret >= 0); (void)ret; } void nrf_802154_clock_hfclk_stop(void) { - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); + struct device *clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); - __ASSERT_NO_MSG(mgr != NULL); + int ret = nrf_clock_control_cancel_or_release(clk_dev, NULL, &hfclk_cli); - int ret = onoff_cancel_or_release(mgr, &hfclk_cli); __ASSERT_NO_MSG(ret >= 0); (void)ret; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_clock.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_clock.c index af98d69b049e..b3200b60fd8a 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_clock.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_clock.c @@ -35,7 +35,7 @@ static void clock_ready(struct onoff_manager *mgr, struct onoff_client *cli, k_sem_give(&clk_state->sem); } -static int blocking_on(struct onoff_manager *mgr, uint32_t timeout) +static int blocking_on(struct device *dev, uint32_t timeout) { struct lll_clock_state state; @@ -43,7 +43,7 @@ static int blocking_on(struct onoff_manager *mgr, uint32_t timeout) k_sem_init(&state.sem, 0, 1); sys_notify_init_callback(&state.cli.notify, clock_ready); - err = onoff_request(mgr, &state.cli); + err = nrf_clock_control_request(dev, NULL, &state.cli); if (err < 0) { return err; } @@ -53,28 +53,20 @@ static int blocking_on(struct onoff_manager *mgr, uint32_t timeout) int lll_clock_init(void) { - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF); - sys_notify_init_spinwait(&lf_cli.notify); - return onoff_request(mgr, &lf_cli); + return nrf_clock_control_request(DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk), NULL, &lf_cli); } int lll_clock_deinit(void) { - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF); - /* Cancel any ongoing request */ - (void)onoff_cancel(mgr, &lf_cli); - - return onoff_release(mgr); + return nrf_clock_control_cancel_or_release(DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk), NULL, + &lf_cli); } int lll_clock_wait(void) { - struct onoff_manager *mgr; static bool done; int err; @@ -83,13 +75,12 @@ int lll_clock_wait(void) } done = true; - mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF); - err = blocking_on(mgr, LFCLOCK_TIMEOUT_MS); + err = blocking_on(DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk), LFCLOCK_TIMEOUT_MS); if (err) { return err; } - err = onoff_release(mgr); + err = nrf_clock_control_release(DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk), NULL); if (err != ONOFF_STATE_ON) { return -EIO; } @@ -111,13 +102,15 @@ int lll_hfclock_on(void) int lll_hfclock_on_wait(void) { - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); int err; atomic_inc(&hf_refcnt); - err = blocking_on(mgr, HFCLOCK_TIMEOUT_MS); + struct device *clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); + + err = blocking_on(clk_dev, HFCLOCK_TIMEOUT_MS); if (err >= 0) { DEBUG_RADIO_XTAL(1); } diff --git a/tests/drivers/clock_control/nrf_clock_calibration/src/test_nrf_clock_calibration.c b/tests/drivers/clock_control/nrf_clock_calibration/src/test_nrf_clock_calibration.c index 794144ff8d40..de64ee115e49 100644 --- a/tests/drivers/clock_control/nrf_clock_calibration/src/test_nrf_clock_calibration.c +++ b/tests/drivers/clock_control/nrf_clock_calibration/src/test_nrf_clock_calibration.c @@ -19,16 +19,14 @@ LOG_MODULE_REGISTER(test); extern void mock_temp_nrf5_value_set(struct sensor_value *val); -static void turn_on_clock(const struct device *dev, - clock_control_subsys_t subsys) +static void turn_on_clock(const struct device *dev) { int err; int res; struct onoff_client cli; - struct onoff_manager *mgr = z_nrf_clock_control_get_onoff(subsys); sys_notify_init_spinwait(&cli.notify); - err = onoff_request(mgr, &cli); + err = nrf_clock_control_request(dev, NULL, &cli); if (err < 0) { zassert_false(true, "Failed to start clock"); } @@ -36,14 +34,12 @@ static void turn_on_clock(const struct device *dev, } } -static void turn_off_clock(const struct device *dev, - clock_control_subsys_t subsys) +static void turn_off_clock(const struct device *dev) { int err; - struct onoff_manager *mgr = z_nrf_clock_control_get_onoff(subsys); do { - err = onoff_release(mgr); + err = nrf_clock_control_release(dev, NULL); } while (err >= 0); while (clock_control_get_status(dev, subsys) != @@ -63,9 +59,11 @@ static void test_calibration(uint32_t exp_cal, uint32_t exp_skip, int cal_cnt; int skip_cnt; - const struct device *const clk_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock); + const struct device *const clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); - turn_on_clock(clk_dev, CLOCK_CONTROL_NRF_SUBSYS_HF); + turn_on_clock(clk_dev); cal_cnt = z_nrf_clock_calibration_count(); skip_cnt = z_nrf_clock_calibration_skips_count(); @@ -75,7 +73,7 @@ static void test_calibration(uint32_t exp_cal, uint32_t exp_skip, cal_cnt = z_nrf_clock_calibration_count() - cal_cnt; skip_cnt = z_nrf_clock_calibration_skips_count() - skip_cnt; - turn_off_clock(clk_dev, CLOCK_CONTROL_NRF_SUBSYS_HF); + turn_off_clock(clk_dev); zassert_equal(cal_cnt, exp_cal, "%d: Unexpected number of calibrations (%d, exp:%d)", @@ -126,18 +124,18 @@ ZTEST(nrf_clock_calibration, test_calibration_after_enabling_lfclk) ztest_test_skip(); } - const struct device *const clk_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock); + const struct device *const clk_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk); struct sensor_value value = { .val1 = 0, .val2 = 0 }; zassert_true(device_is_ready(clk_dev), "Device is not ready"); mock_temp_nrf5_value_set(&value); - turn_off_clock(clk_dev, CLOCK_CONTROL_NRF_SUBSYS_LF); + turn_off_clock(clk_dev); k_busy_wait(10000); - turn_on_clock(clk_dev, CLOCK_CONTROL_NRF_SUBSYS_LF); + turn_on_clock(clk_dev); TEST_CALIBRATION(1, 0, CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD); diff --git a/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c b/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c index 0224e986ff4d..e902070e22c0 100644 --- a/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c +++ b/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c @@ -20,7 +20,7 @@ static bool test_end; static const struct device *const entropy = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); static const struct device *const clock_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock); -static struct onoff_manager *hf_mgr; +static struct device *hf_dev; static struct onoff_client cli; static uint32_t iteration; @@ -29,8 +29,10 @@ static void *setup(void) zassert_true(device_is_ready(entropy)); zassert_true(device_is_ready(clock_dev)); - hf_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); - zassert_true(hf_mgr); + hf_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); + zassert_true(hf_dev); return NULL; } @@ -115,7 +117,7 @@ ZTEST(nrf_onoff_and_bt, test_onoff_interrupted) backoff = 3 * rand; sys_notify_init_spinwait(&cli.notify); - err = onoff_request(hf_mgr, &cli); + err = nrf_clock_control_request(hf_dev, NULL, &cli); zassert_true(err >= 0); k_busy_wait(backoff); @@ -124,7 +126,7 @@ ZTEST(nrf_onoff_and_bt, test_onoff_interrupted) check_hf_status(clock_dev, true, true); } - err = onoff_cancel_or_release(hf_mgr, &cli); + err = nrf_clock_control_cancel_or_release(hf_dev, NULL, &cli); zassert_true(err >= 0); elapsed = k_uptime_get() - start_time; diff --git a/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c b/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c index 29b235d2b5ec..382f9509f76e 100644 --- a/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c +++ b/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c @@ -10,10 +10,9 @@ LOG_MODULE_REGISTER(test); #include -static struct onoff_manager *get_mgr(void) -{ - return z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); -} + static struct device *dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); static bool clock_is_off(void) { @@ -27,10 +26,8 @@ static bool clock_is_off(void) static void clock_off(void) { - struct onoff_manager *mgr = get_mgr(); - do { - (void)onoff_release(mgr); + (void)nrf_clock_control_release(dev, NULL); } while (!clock_is_off()); } @@ -38,13 +35,12 @@ static void clock_off(void) ZTEST(clock_control_onoff, test_clock_blocking_on) { struct onoff_client cli; - struct onoff_manager *mgr = get_mgr(); int err; clock_off(); sys_notify_init_spinwait(&cli.notify); - err = onoff_request(mgr, &cli); + err = nrf_clock_control_request(dev, NULL, &cli); zassert_true(err >= 0, ""); while (sys_notify_fetch_result(&cli.notify, &err) < 0) { @@ -54,25 +50,24 @@ ZTEST(clock_control_onoff, test_clock_blocking_on) /* clock on, now turn it off */ - err = onoff_release(mgr); + err = nrf_clock_control_release(dev, NULL); zassert_true(err >= 0, ""); } ZTEST(clock_control_onoff, test_clock_spinwait_release_before_start) { struct onoff_client cli; - struct onoff_manager *mgr = get_mgr(); int err; clock_off(); k_busy_wait(10000); sys_notify_init_spinwait(&cli.notify); - err = onoff_request(mgr, &cli); + err = nrf_clock_control_request(dev, NULL, &cli); zassert_true(err >= 0, "err: %d", err); /* Attempt to release while ongoing start. Cannot do that */ - err = onoff_cancel_or_release(mgr, &cli); + err = nrf_clock_control_cancel_or_release(dev, NULL, &cli); zassert_true(err >= 0, "err: %d", err); k_busy_wait(100000); @@ -96,14 +91,13 @@ static void request_cb(struct onoff_manager *mgr, struct onoff_client *cli, ZTEST(clock_control_onoff, test_clock_release_from_callback) { struct onoff_client cli; - struct onoff_manager *mgr = get_mgr(); int err; clock_off(); k_busy_wait(100); sys_notify_init_callback(&cli.notify, request_cb); - err = onoff_request(mgr, &cli); + err = nrf_clock_control_request(dev, NULL, &cli); zassert_true(err >= 0, "err: %d", err); k_busy_wait(100000); From eb621f6ee7f13ee6495bec5e0c4a35ba4f7e0dfe Mon Sep 17 00:00:00 2001 From: Michal Frankiewicz Date: Mon, 17 Nov 2025 16:01:57 +0100 Subject: [PATCH 9/9] [nrf fromlist] treewide: Replace single clock api with separated clock api. Replaced clock_control_nrf, nrfx_clock api usecases with clock speciffic api. Upstream PR #: 99290 Signed-off-by: Michal Frankiewicz --- drivers/clock_control/CMakeLists.txt | 1 - drivers/clock_control/clock_control_nrf.c | 778 ------------------ .../clock_control/clock_control_nrf_common.c | 4 - drivers/clock_control/nrf_clock_calibration.c | 4 +- samples/boards/nordic/clock_skew/src/main.c | 37 +- samples/net/zperf/src/nrf5340_cpu_boost.c | 4 +- subsys/bluetooth/audio/shell/bap_usb.c | 4 +- .../clock_control_api/src/nrf_device_subsys.h | 12 +- .../nrf_lf_clock_start/src/main.c | 7 +- .../clock_control/nrf_onoff_and_bt/src/main.c | 42 +- .../onoff/src/test_clock_control_onoff.c | 6 +- 11 files changed, 70 insertions(+), 829 deletions(-) delete mode 100644 drivers/clock_control/clock_control_nrf.c diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index acdcd3b532e4..229a465df418 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -23,7 +23,6 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SYSCON clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MSPM0 clock_control_mspm0.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NPCM clock_control_npcm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NPCX clock_control_npcx.c) -zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF clock_control_nrf.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION nrf_clock_calibration.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RV32M1_PCC clock_control_rv32m1_pcc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_INFINEON_CAT1 clock_control_ifx_cat1.c) diff --git a/drivers/clock_control/clock_control_nrf.c b/drivers/clock_control/clock_control_nrf.c deleted file mode 100644 index 2ffe5cb694e9..000000000000 --- a/drivers/clock_control/clock_control_nrf.c +++ /dev/null @@ -1,778 +0,0 @@ -/* - * Copyright (c) 2016-2020 Nordic Semiconductor ASA - * Copyright (c) 2016 Vinayak Kariappa Chettimada - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include "nrf_clock_calibration.h" -#include "clock_control_nrf_common.h" -#include -#include -#include -#include - -LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL); - -#define DT_DRV_COMPAT nordic_nrf_clock - - -#define CTX_ONOFF BIT(6) -#define CTX_API BIT(7) -#define CTX_MASK (CTX_ONOFF | CTX_API) - -#define STATUS_MASK 0x7 -#define GET_STATUS(flags) (flags & STATUS_MASK) -#define GET_CTX(flags) (flags & CTX_MASK) - -/* Used only by HF clock */ -#define HF_USER_BT BIT(0) -#define HF_USER_GENERIC BIT(1) - -/* Helper logging macros which prepends subsys name to the log. */ -#ifdef CONFIG_LOG -#define CLOCK_LOG(lvl, dev, subsys, ...) \ - LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \ - get_sub_config(dev, (enum clock_control_nrf_type)subsys)->name \ - COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__),\ - (), (, GET_ARGS_LESS_N(1, __VA_ARGS__)))) -#else -#define CLOCK_LOG(...) -#endif - -#define ERR(dev, subsys, ...) CLOCK_LOG(ERR, dev, subsys, __VA_ARGS__) -#define WRN(dev, subsys, ...) CLOCK_LOG(WRN, dev, subsys, __VA_ARGS__) -#define INF(dev, subsys, ...) CLOCK_LOG(INF, dev, subsys, __VA_ARGS__) -#define DBG(dev, subsys, ...) CLOCK_LOG(DBG, dev, subsys, __VA_ARGS__) - -/* Clock subsys structure */ -struct nrf_clock_control_sub_data { - clock_control_cb_t cb; - void *user_data; - uint32_t flags; -}; - -typedef void (*clk_ctrl_func_t)(void); - -/* Clock subsys static configuration */ -struct nrf_clock_control_sub_config { - clk_ctrl_func_t start; /* Clock start function */ - clk_ctrl_func_t stop; /* Clock stop function */ -#ifdef CONFIG_LOG - const char *name; -#endif -}; - -struct nrf_clock_control_data { - struct onoff_manager mgr[CLOCK_CONTROL_NRF_TYPE_COUNT]; - struct nrf_clock_control_sub_data subsys[CLOCK_CONTROL_NRF_TYPE_COUNT]; -}; - -struct nrf_clock_control_config { - struct nrf_clock_control_sub_config - subsys[CLOCK_CONTROL_NRF_TYPE_COUNT]; -}; - -static atomic_t hfclk_users; -static uint64_t hf_start_tstamp; -static uint64_t hf_stop_tstamp; -#if CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH -/* Client to request HFXO to synthesize low frequency clock. */ -static struct onoff_client lfsynth_cli; -#endif - -static struct nrf_clock_control_sub_data *get_sub_data(const struct device *dev, - enum clock_control_nrf_type type) -{ - struct nrf_clock_control_data *data = dev->data; - - return &data->subsys[type]; -} - -static const struct nrf_clock_control_sub_config *get_sub_config(const struct device *dev, - enum clock_control_nrf_type type) -{ - const struct nrf_clock_control_config *config = - dev->config; - - return &config->subsys[type]; -} - -static struct onoff_manager *get_onoff_manager(const struct device *dev, - enum clock_control_nrf_type type) -{ - struct nrf_clock_control_data *data = dev->data; - - return &data->mgr[type]; -} - - -#define CLOCK_DEVICE DEVICE_DT_GET(DT_NODELABEL(clock)) - -struct onoff_manager *z_nrf_clock_control_get_onoff(clock_control_subsys_t sys) -{ - return get_onoff_manager(CLOCK_DEVICE, - (enum clock_control_nrf_type)(size_t)sys); -} - -static enum clock_control_status get_status(const struct device *dev, - clock_control_subsys_t subsys) -{ - enum clock_control_nrf_type type = (enum clock_control_nrf_type)(size_t)subsys; - - __ASSERT_NO_MSG(type < CLOCK_CONTROL_NRF_TYPE_COUNT); - - return GET_STATUS(get_sub_data(dev, type)->flags); -} - -static int set_off_state(uint32_t *flags, uint32_t ctx) -{ - int err = 0; - unsigned int key = irq_lock(); - uint32_t current_ctx = GET_CTX(*flags); - - if ((current_ctx != 0) && (current_ctx != ctx)) { - err = -EPERM; - } else { - *flags = CLOCK_CONTROL_STATUS_OFF; - } - - irq_unlock(key); - - return err; -} - -static int set_starting_state(uint32_t *flags, uint32_t ctx) -{ - int err = 0; - unsigned int key = irq_lock(); - uint32_t current_ctx = GET_CTX(*flags); - - if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) { - *flags = CLOCK_CONTROL_STATUS_STARTING | ctx; - } else if (current_ctx != ctx) { - err = -EPERM; - } else { - err = -EALREADY; - } - - irq_unlock(key); - - return err; -} - -static void set_on_state(uint32_t *flags) -{ - unsigned int key = irq_lock(); - - *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags); - irq_unlock(key); -} - -#ifdef CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION - -static void nrf54l_errata_30_workaround(void) -{ - while (FIELD_GET(CLOCK_XO_STAT_STATE_Msk, NRF_CLOCK->XO.STAT) != - CLOCK_XO_STAT_STATE_Running) { - } - const uint32_t higher_bits = *((volatile uint32_t *)0x50120820UL) & 0xFFFFFFC0; - *((volatile uint32_t *)0x50120864UL) = 1 | BIT(31); - *((volatile uint32_t *)0x50120848UL) = 1; - uint32_t off_abs = 24; - - while (off_abs >= 24) { - *((volatile uint32_t *)0x50120844UL) = 1; - while (((*((volatile uint32_t *)0x50120840UL)) & (1 << 16)) != 0) { - } - const uint32_t current_cal = *((volatile uint32_t *)0x50120820UL) & 0x3F; - const uint32_t cal_result = *((volatile uint32_t *)0x50120840UL) & 0x7FF; - int32_t off = 1024 - cal_result; - - off_abs = (off < 0) ? -off : off; - - if (off >= 24 && current_cal < 0x3F) { - *((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal + 1); - } else if (off <= -24 && current_cal > 0) { - *((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal - 1); - } - } - - *((volatile uint32_t *)0x50120848UL) = 0; - *((volatile uint32_t *)0x50120864UL) = 0; -} - -#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD - -static struct onoff_client hf_cal_cli; - -static void calibration_finished_callback(struct onoff_manager *mgr, - struct onoff_client *cli, - uint32_t state, - int res) -{ - (void)onoff_cancel_or_release(mgr, cli); -} - -static void calibration_handler(struct k_timer *timer) -{ - nrf_clock_hfclk_t clk_src; - - bool ret = nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &clk_src); - - if (ret && (clk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY)) { - return; - } - - sys_notify_init_callback(&hf_cal_cli.notify, calibration_finished_callback); - (void)onoff_request(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF), - &hf_cal_cli); -} - -static K_TIMER_DEFINE(calibration_timer, calibration_handler, NULL); - -static int calibration_init(void) -{ - k_timer_start(&calibration_timer, - K_NO_WAIT, - K_MSEC(CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD)); - - return 0; -} - -SYS_INIT(calibration_init, APPLICATION, 0); - -#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD */ -#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION */ - -static void clkstarted_handle(const struct device *dev, - enum clock_control_nrf_type type) -{ -#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION - if (nrf54l_errata_30() && (type == CLOCK_CONTROL_NRF_TYPE_HFCLK)) { - nrf54l_errata_30_workaround(); - } -#endif - struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type); - clock_control_cb_t callback = sub_data->cb; - void *user_data = sub_data->user_data; - - sub_data->cb = NULL; - set_on_state(&sub_data->flags); - DBG(dev, type, "Clock started"); - - if (callback) { - callback(dev, (clock_control_subsys_t)type, user_data); - } -} - -static inline void anomaly_132_workaround(void) -{ -#if (CONFIG_NRF52_ANOMALY_132_DELAY_US - 0) - static bool once; - - if (!once) { - k_busy_wait(CONFIG_NRF52_ANOMALY_132_DELAY_US); - once = true; - } -#endif -} - -static void lfclk_start(void) -{ - if (IS_ENABLED(CONFIG_NRF52_ANOMALY_132_WORKAROUND)) { - anomaly_132_workaround(); - } - -#if CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH - sys_notify_init_spinwait(&lfsynth_cli.notify); - (void)onoff_request(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF), - &lfsynth_cli); -#endif - - nrfx_clock_lfclk_start(); -} - -static void lfclk_stop(void) -{ - if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { - z_nrf_clock_calibration_lfclk_stopped(); - } - - nrfx_clock_lfclk_stop(); - -#if CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH - (void)onoff_cancel_or_release(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF), - &lfsynth_cli); -#endif -} - -static void hfclk_start(void) -{ - if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) { - hf_start_tstamp = k_uptime_get(); - } - - nrfx_clock_start(NRF_CLOCK_DOMAIN_HFCLK); -} - -static void hfclk_stop(void) -{ - if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) { - hf_stop_tstamp = k_uptime_get(); - } - - nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK); -} - -#if NRF_CLOCK_HAS_HFCLK24M -static void hfclk24m_start(void) -{ - nrfx_clock_start(NRF_CLOCK_DOMAIN_HFCLK24M); -} - -static void hfclk24m_stop(void) -{ - nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK24M); -} -#endif - -#if NRF_CLOCK_HAS_HFCLK192M -static void hfclk192m_start(void) -{ - nrfx_clock_start(NRF_CLOCK_DOMAIN_HFCLK192M); -} - -static void hfclk192m_stop(void) -{ - nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK192M); -} -#endif - -#if NRF_CLOCK_HAS_HFCLKAUDIO -static void hfclkaudio_start(void) -{ - nrfx_clock_start(NRF_CLOCK_DOMAIN_HFCLKAUDIO); -} - -static void hfclkaudio_stop(void) -{ - nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLKAUDIO); -} -#endif - -static uint32_t *get_hf_flags(void) -{ - struct nrf_clock_control_data *data = CLOCK_DEVICE->data; - - return &data->subsys[CLOCK_CONTROL_NRF_TYPE_HFCLK].flags; -} - -static void generic_hfclk_start(void) -{ - nrf_clock_hfclk_t type; - bool already_started = false; - unsigned int key = irq_lock(); - - hfclk_users |= HF_USER_GENERIC; - if (hfclk_users & HF_USER_BT) { - (void)nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &type); - if (type == NRF_CLOCK_HFCLK_HIGH_ACCURACY) { - already_started = true; - /* Set on state in case clock interrupt comes and we - * want to avoid handling that. - */ - set_on_state(get_hf_flags()); - } - } - - irq_unlock(key); - - if (already_started) { - /* Clock already started by z_nrf_clock_bt_ctlr_hf_request */ - clkstarted_handle(CLOCK_DEVICE, - CLOCK_CONTROL_NRF_TYPE_HFCLK); - return; - } - - hfclk_start(); -} - -static void generic_hfclk_stop(void) -{ - /* It's not enough to use only atomic_and() here for synchronization, - * as the thread could be preempted right after that function but - * before hfclk_stop() is called and the preempting code could request - * the HFCLK again. Then, the HFCLK would be stopped inappropriately - * and hfclk_user would be left with an incorrect value. - */ - unsigned int key = irq_lock(); - - hfclk_users &= ~HF_USER_GENERIC; - /* Skip stopping if BT is still requesting the clock. */ - if (!(hfclk_users & HF_USER_BT)) { - hfclk_stop(); - } - - irq_unlock(key); -} - -static int stop(const struct device *dev, clock_control_subsys_t subsys, - uint32_t ctx) -{ - enum clock_control_nrf_type type = (enum clock_control_nrf_type)(size_t)subsys; - struct nrf_clock_control_sub_data *subdata = get_sub_data(dev, type); - int err; - - __ASSERT_NO_MSG(type < CLOCK_CONTROL_NRF_TYPE_COUNT); - - err = set_off_state(&subdata->flags, ctx); - if (err < 0) { - return err; - } - - get_sub_config(dev, type)->stop(); - - return 0; -} - -static int api_stop(const struct device *dev, clock_control_subsys_t subsys) -{ - return stop(dev, subsys, CTX_API); -} - -static int async_start(const struct device *dev, clock_control_subsys_t subsys, - clock_control_cb_t cb, void *user_data, uint32_t ctx) -{ - enum clock_control_nrf_type type = (enum clock_control_nrf_type)(size_t)subsys; - struct nrf_clock_control_sub_data *subdata = get_sub_data(dev, type); - int err; - - err = set_starting_state(&subdata->flags, ctx); - if (err < 0) { - return err; - } - - subdata->cb = cb; - subdata->user_data = user_data; - - get_sub_config(dev, type)->start(); - - return 0; -} - -static int api_start(const struct device *dev, clock_control_subsys_t subsys, - clock_control_cb_t cb, void *user_data) -{ - return async_start(dev, subsys, cb, user_data, CTX_API); -} - -static void blocking_start_callback(const struct device *dev, - clock_control_subsys_t subsys, - void *user_data) -{ - struct k_sem *sem = user_data; - - k_sem_give(sem); -} - -static int api_blocking_start(const struct device *dev, - clock_control_subsys_t subsys) -{ - struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1); - int err; - - if (!IS_ENABLED(CONFIG_MULTITHREADING)) { - return -ENOTSUP; - } - - err = api_start(dev, subsys, blocking_start_callback, &sem); - if (err < 0) { - return err; - } - - return k_sem_take(&sem, K_MSEC(500)); -} - -static clock_control_subsys_t get_subsys(struct onoff_manager *mgr) -{ - struct nrf_clock_control_data *data = CLOCK_DEVICE->data; - size_t offset = (size_t)(mgr - data->mgr); - - return (clock_control_subsys_t)offset; -} - -static void onoff_stop(struct onoff_manager *mgr, - onoff_notify_fn notify) -{ - int res; - - res = stop(CLOCK_DEVICE, get_subsys(mgr), CTX_ONOFF); - notify(mgr, res); -} - -static void onoff_started_callback(const struct device *dev, - clock_control_subsys_t sys, - void *user_data) -{ - enum clock_control_nrf_type type = (enum clock_control_nrf_type)(size_t)sys; - struct onoff_manager *mgr = get_onoff_manager(dev, type); - onoff_notify_fn notify = user_data; - - notify(mgr, 0); -} - -static void onoff_start(struct onoff_manager *mgr, - onoff_notify_fn notify) -{ - int err; - - err = async_start(CLOCK_DEVICE, get_subsys(mgr), - onoff_started_callback, notify, CTX_ONOFF); - if (err < 0) { - notify(mgr, err); - } -} - -static void clock_event_handler(nrfx_clock_evt_type_t event) -{ - const struct device *dev = CLOCK_DEVICE; - - switch (event) { -#if NRF_CLOCK_HAS_XO_TUNE - case NRFX_CLOCK_EVT_XO_TUNED: - clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK); - break; - case NRFX_CLOCK_EVT_XO_TUNE_ERROR: - case NRFX_CLOCK_EVT_XO_TUNE_FAILED: - /* No processing needed. */ - break; - case NRFX_CLOCK_EVT_HFCLK_STARTED: - /* HFCLK is stable after XOTUNED event. - * HFCLK_STARTED means only that clock has been started. - */ - break; -#else - /* HFCLK started should be used only if tune operation is done implicitly. */ - case NRFX_CLOCK_EVT_HFCLK_STARTED: - { - struct nrf_clock_control_sub_data *data = - get_sub_data(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK); - - /* Check needed due to anomaly 201: - * HFCLKSTARTED may be generated twice. - */ - if (GET_STATUS(data->flags) == CLOCK_CONTROL_STATUS_STARTING) { - clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK); - } - - break; - } -#endif -#if NRF_CLOCK_HAS_HFCLK24M - case NRFX_CLOCK_EVT_HFCLK24M_STARTED: - clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK24M); - break; -#endif -#if NRF_CLOCK_HAS_HFCLK192M - case NRFX_CLOCK_EVT_HFCLK192M_STARTED: - clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK192M); - break; -#endif -#if NRF_CLOCK_HAS_HFCLKAUDIO - case NRFX_CLOCK_EVT_HFCLKAUDIO_STARTED: - clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLKAUDIO); - break; -#endif - case NRFX_CLOCK_EVT_LFCLK_STARTED: - if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { - z_nrf_clock_calibration_lfclk_started(); - } - clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_LFCLK); - break; -#if NRF_CLOCK_HAS_CALIBRATION || NRF_LFRC_HAS_CALIBRATION - case NRFX_CLOCK_EVT_CAL_DONE: - if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { - z_nrf_clock_calibration_done_handler(); - } else { - /* Should not happen when calibration is disabled. */ - __ASSERT_NO_MSG(false); - } - break; -#endif -#if NRF_CLOCK_HAS_PLL - case NRFX_CLOCK_EVT_PLL_STARTED: - /* No processing needed. */ - break; -#endif - default: - __ASSERT_NO_MSG(0); - break; - } -} - -static void hfclkaudio_init(void) -{ -#if DT_NODE_HAS_PROP(DT_NODELABEL(clock), hfclkaudio_frequency) - const uint32_t frequency = - DT_PROP(DT_NODELABEL(clock), hfclkaudio_frequency); - /* As specified in the nRF5340 PS: - * - * FREQ_VALUE = 2^16 * ((12 * f_out / 32M) - 4) - */ - const uint32_t freq_value = - (uint32_t)((384ULL * frequency) / 15625) - 262144; - -#if NRF_CLOCK_HAS_HFCLKAUDIO - nrf_clock_hfclkaudio_config_set(NRF_CLOCK, freq_value); -#else -#error "hfclkaudio-frequency specified but HFCLKAUDIO clock is not present." -#endif /* NRF_CLOCK_HAS_HFCLKAUDIO */ -#endif -} - -static int clk_init(const struct device *dev) -{ - int err; - static const struct onoff_transitions transitions = { - .start = onoff_start, - .stop = onoff_stop - }; - -#if NRF_LFRC_HAS_CALIBRATION - IRQ_CONNECT(LFRC_IRQn, DT_INST_IRQ(0, priority), nrfx_isr, nrfx_power_clock_irq_handler, 0); -#endif - clock_control_nrf_common_connect_irq(); - - if (nrfx_clock_init(clock_event_handler) != 0) { - return -EIO; - } - - hfclkaudio_init(); - - if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { - z_nrf_clock_calibration_init(); - } - - nrfx_clock_enable(); - - for (enum clock_control_nrf_type i = 0; - i < CLOCK_CONTROL_NRF_TYPE_COUNT; i++) { - struct nrf_clock_control_sub_data *subdata = - get_sub_data(dev, i); - - err = onoff_manager_init(get_onoff_manager(dev, i), - &transitions); - if (err < 0) { - return err; - } - - subdata->flags = CLOCK_CONTROL_STATUS_OFF; - } - - return 0; -} - -static DEVICE_API(clock_control, clock_control_api) = { - .on = api_blocking_start, - .off = api_stop, - .async_on = api_start, - .get_status = get_status, -}; - -static struct nrf_clock_control_data data; - -static const struct nrf_clock_control_config config = { - .subsys = { - [CLOCK_CONTROL_NRF_TYPE_HFCLK] = { - .start = generic_hfclk_start, - .stop = generic_hfclk_stop, - IF_ENABLED(CONFIG_LOG, (.name = "hfclk",)) - }, - [CLOCK_CONTROL_NRF_TYPE_LFCLK] = { - .start = lfclk_start, - .stop = lfclk_stop, - IF_ENABLED(CONFIG_LOG, (.name = "lfclk",)) - }, -#if NRF_CLOCK_HAS_HFCLK24M - [CLOCK_CONTROL_NRF_TYPE_HFCLK24M] = { - .start = hfclk24m_start, - .stop = hfclk24m_stop, - IF_ENABLED(CONFIG_LOG, (.name = "hfclk24m",)) - }, -#endif -#if NRF_CLOCK_HAS_HFCLK192M - [CLOCK_CONTROL_NRF_TYPE_HFCLK192M] = { - .start = hfclk192m_start, - .stop = hfclk192m_stop, - IF_ENABLED(CONFIG_LOG, (.name = "hfclk192m",)) - }, -#endif -#if NRF_CLOCK_HAS_HFCLKAUDIO - [CLOCK_CONTROL_NRF_TYPE_HFCLKAUDIO] = { - .start = hfclkaudio_start, - .stop = hfclkaudio_stop, - IF_ENABLED(CONFIG_LOG, (.name = "hfclkaudio",)) - }, -#endif - } -}; - -DEVICE_DT_DEFINE(DT_NODELABEL(clock), clk_init, NULL, - &data, &config, - PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, - &clock_control_api); - -#if defined(CONFIG_SHELL) - -static int cmd_status(const struct shell *sh, size_t argc, char **argv) -{ - nrf_clock_hfclk_t hfclk_src; - bool hf_status; - bool lf_status = nrfx_clock_is_running(NRF_CLOCK_DOMAIN_LFCLK, NULL); - struct onoff_manager *hf_mgr = - get_onoff_manager(CLOCK_DEVICE, - CLOCK_CONTROL_NRF_TYPE_HFCLK); - struct onoff_manager *lf_mgr = - get_onoff_manager(CLOCK_DEVICE, - CLOCK_CONTROL_NRF_TYPE_LFCLK); - uint32_t abs_start, abs_stop; - unsigned int key = irq_lock(); - uint64_t now = k_uptime_get(); - - (void)nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, (void *)&hfclk_src); - hf_status = (hfclk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY); - - abs_start = hf_start_tstamp; - abs_stop = hf_stop_tstamp; - irq_unlock(key); - - shell_print(sh, "HF clock:"); - shell_print(sh, "\t- %srunning (users: %u)", - hf_status ? "" : "not ", hf_mgr->refs); - shell_print(sh, "\t- last start: %u ms (%u ms ago)", - (uint32_t)abs_start, (uint32_t)(now - abs_start)); - shell_print(sh, "\t- last stop: %u ms (%u ms ago)", - (uint32_t)abs_stop, (uint32_t)(now - abs_stop)); - shell_print(sh, "LF clock:"); - shell_print(sh, "\t- %srunning (users: %u)", - lf_status ? "" : "not ", lf_mgr->refs); - - return 0; -} - -SHELL_STATIC_SUBCMD_SET_CREATE(subcmds, - SHELL_CMD_ARG(status, NULL, "Status", cmd_status, 1, 0), - SHELL_SUBCMD_SET_END -); - -SHELL_COND_CMD_REGISTER(CONFIG_CLOCK_CONTROL_NRF_SHELL, - nrf_clock_control, &subcmds, - "Clock control commands", - cmd_status); - -#endif /* defined(CONFIG_SHELL) */ diff --git a/drivers/clock_control/clock_control_nrf_common.c b/drivers/clock_control/clock_control_nrf_common.c index 8c7b5aab17f1..a6470f0787bd 100644 --- a/drivers/clock_control/clock_control_nrf_common.c +++ b/drivers/clock_control/clock_control_nrf_common.c @@ -5,7 +5,6 @@ #include "clock_control_nrf_common.h" #include -#include #if NRFX_CHECK(NRFX_POWER_ENABLED) #include @@ -24,9 +23,6 @@ static void clock_irq_handler(void) STRUCT_SECTION_FOREACH(clock_control_nrf_irq_handler, irq) { irq->handler(); } - - /* temporary fix, it will be removed when all the clocks are moved to their files */ - nrfx_clock_irq_handler(); } void clock_control_nrf_common_connect_irq(void) diff --git a/drivers/clock_control/nrf_clock_calibration.c b/drivers/clock_control/nrf_clock_calibration.c index b6b7d41237b8..4f4dc347b645 100644 --- a/drivers/clock_control/nrf_clock_calibration.c +++ b/drivers/clock_control/nrf_clock_calibration.c @@ -7,7 +7,7 @@ #include #include "nrf_clock_calibration.h" #include -#include +#include #include #include @@ -119,7 +119,7 @@ static void cal_lf_callback(struct onoff_manager *mgr, /* Start actual HW calibration assuming that HFCLK XTAL is on. */ static void start_hw_cal(void) { - nrfx_clock_calibration_start(); + nrfx_clock_lfclk_calibration_start(); calib_skip_cnt = CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_MAX_SKIP; } diff --git a/samples/boards/nordic/clock_skew/src/main.c b/samples/boards/nordic/clock_skew/src/main.c index 57a770e4db49..e4097eb579c0 100644 --- a/samples/boards/nordic/clock_skew/src/main.c +++ b/samples/boards/nordic/clock_skew/src/main.c @@ -10,11 +10,19 @@ #include #include #include -#include +#include +#include + +#if NRF_CLOCK_HAS_HFCLK +#include +#elif NRF_CLOCK_HAS_XO +#include +#else +#error "HF clock not enabled" +#endif #define UPDATE_INTERVAL_S 10 -static const struct device *const clock0 = DEVICE_DT_GET_ONE(nordic_nrf_clock); static const struct device *const timer0 = DEVICE_DT_GET(DT_NODELABEL(timer0)); static struct timeutil_sync_config sync_config; static uint64_t counter_ref; @@ -100,14 +108,18 @@ static void show_clocks(const char *tag) enum clock_control_status clkstat; bool running; - clkstat = clock_control_get_status(clock0, CLOCK_CONTROL_NRF_SUBSYS_LF); - running = nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, - &src.lf); + clkstat = clock_control_get_status(DEVICE_DT_GET_ONE(nordic_nrf_clock_lfclk), NULL); + running = nrfx_clock_lfclk_running_check(&src.lf); printk("%s: LFCLK[%s]: %s %s ; ", tag, clkstat_s[clkstat], running ? "Running" : "Off", lfsrc_s[src.lf]); - clkstat = clock_control_get_status(clock0, CLOCK_CONTROL_NRF_SUBSYS_HF); - running = nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_HFCLK, - &src.hf); + clkstat = clock_control_get_status(DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))), + NULL); + + running = COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nrfx_clock_hfclk_running_check), + (nrfx_clock_xo_running_check))(&src.hf); printk("HFCLK[%s]: %s %s\n", clkstat_s[clkstat], running ? "Running" : "Off", hfsrc_s[src.hf]); } @@ -196,19 +208,22 @@ static void sync_work_handler(struct k_work *work) int main(void) { + struct device *clk_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); uint32_t top; int rc; /* Grab the clock driver */ - if (!device_is_ready(clock0)) { - printk("%s: device not ready.\n", clock0->name); + if (!device_is_ready(clk_dev)) { + printk("%s: device not ready.\n", clk_dev->name); return 0; } show_clocks("Power-up clocks"); if (IS_ENABLED(CONFIG_APP_ENABLE_HFXO)) { - rc = clock_control_on(clock0, CLOCK_CONTROL_NRF_SUBSYS_HF); + rc = clock_control_on(clk_dev, NULL); printk("Enable HFXO got %d\n", rc); } diff --git a/samples/net/zperf/src/nrf5340_cpu_boost.c b/samples/net/zperf/src/nrf5340_cpu_boost.c index f1704ebbf818..76fafa28a0c0 100644 --- a/samples/net/zperf/src/nrf5340_cpu_boost.c +++ b/samples/net/zperf/src/nrf5340_cpu_boost.c @@ -12,7 +12,7 @@ #include #include -#include +#include LOG_MODULE_DECLARE(zperf, CONFIG_NET_ZPERF_LOG_LEVEL); @@ -21,7 +21,7 @@ static int nrf53_cpu_boost(void) int err; /* For optimal performance, the CPU frequency should be set to 128 MHz */ - err = nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK, NRF_CLOCK_HFCLK_DIV_1); + err = nrfx_clock_hfclk_divider_set(NRF_CLOCK_HFCLK_DIV_1); if (err != 0) { LOG_WRN("Failed to set 128 MHz: %d", err); } diff --git a/subsys/bluetooth/audio/shell/bap_usb.c b/subsys/bluetooth/audio/shell/bap_usb.c index 07e846fe3623..d5a957aa2aa9 100644 --- a/subsys/bluetooth/audio/shell/bap_usb.c +++ b/subsys/bluetooth/audio/shell/bap_usb.c @@ -36,7 +36,7 @@ #include #if defined(CONFIG_SOC_NRF5340_CPUAPP) -#include +#include #include #include #endif /* CONFIG_SOC_NRF5340_CPUAPP */ @@ -736,7 +736,7 @@ int bap_usb_init(void) * This may not be required, but reduces the risk of not decoding fast enough * to keep up with USB */ - err = nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK, NRF_CLOCK_HFCLK_DIV_1); + err = nrfx_clock_hfclk_divider_set(NRF_CLOCK_HFCLK_DIV_1); if (err != 0) { LOG_WRN("Failed to set 128 MHz: %d", err); diff --git a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h index 5960d8f5e06c..56eb26646cc5 100644 --- a/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h +++ b/tests/drivers/clock_control/clock_control_api/src/nrf_device_subsys.h @@ -10,7 +10,7 @@ #if NRF_CLOCK_HAS_HFCLK static const struct device_subsys_data subsys_data_hfclk[] = { { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, + .subsys = NULL, .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US } }; @@ -18,7 +18,7 @@ static const struct device_subsys_data subsys_data_hfclk[] = { #if NRF_CLOCK_HAS_XO static const struct device_subsys_data subsys_data_xo[] = { { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF, + .subsys = NULL, .startup_us = CONFIG_TEST_NRF_HF_STARTUP_TIME_US } }; @@ -26,7 +26,7 @@ static const struct device_subsys_data subsys_data_xo[] = { #if !defined(CONFIG_SOC_NRF52832) static const struct device_subsys_data subsys_data_lfclk[] = { { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_LF, + .subsys = NULL, .startup_us = (CLOCK_CONTROL_NRF_K32SRC == NRF_CLOCK_LFCLK_RC) ? 1000 : 500000 } @@ -35,7 +35,7 @@ static const struct device_subsys_data subsys_data_lfclk[] = { #if NRF_CLOCK_HAS_HFCLK192M static const struct device_subsys_data subsys_data_hfclk192m[] = { { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF192M, + .subsys = NULL, .startup_us = 5 } }; @@ -43,7 +43,7 @@ static const struct device_subsys_data subsys_data_hfclk192m[] = { #if NRF_CLOCK_HAS_HFCLKAUDIO static const struct device_subsys_data subsys_data_hfclkaudio[] = { { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_HFAUDIO, + .subsys = NULL, .startup_us = 30 } }; @@ -51,7 +51,7 @@ static const struct device_subsys_data subsys_data_hfclkaudio[] = { #if NRF_CLOCK_HAS_XO24M static const struct device_subsys_data subsys_data_xo24m[] = { { - .subsys = CLOCK_CONTROL_NRF_SUBSYS_HF24M, + .subsys = NULL, .startup_us = 5 } }; diff --git a/tests/drivers/clock_control/nrf_lf_clock_start/src/main.c b/tests/drivers/clock_control/nrf_lf_clock_start/src/main.c index b2524e944091..d8060eb7f60a 100644 --- a/tests/drivers/clock_control/nrf_lf_clock_start/src/main.c +++ b/tests/drivers/clock_control/nrf_lf_clock_start/src/main.c @@ -5,6 +5,7 @@ */ #include #include +#include #include static nrf_clock_lfclk_t clk_type; @@ -74,13 +75,13 @@ ZTEST(nrf_lf_clock_start, test_wait_in_thread) } z_nrf_clock_control_lf_on(CLOCK_CONTROL_NRF_LF_START_AVAILABLE); - o = nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &t); + o = nrfx_clock_lfclk_running_check(&t); zassert_false((t == NRF_CLOCK_LFCLK_XTAL) && o); k_busy_wait(35); zassert_true(k_cycle_get_32() > 0); z_nrf_clock_control_lf_on(CLOCK_CONTROL_NRF_LF_START_STABLE); - o = nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &t); + o = nrfx_clock_lfclk_running_check(&t); zassert_true((t == NRF_CLOCK_LFCLK_XTAL) && o); } @@ -118,7 +119,7 @@ static int get_lfclk_state(void) * not valid, in that case read system clock to check if it has * progressed. */ - clk_on = nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &clk_type); + clk_on = nrfx_clock_lfclk_running_check(&clk_type); k_busy_wait(100); rtc_cnt = k_cycle_get_32(); diff --git a/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c b/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c index e902070e22c0..a5eb722e2cc3 100644 --- a/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c +++ b/tests/drivers/clock_control/nrf_onoff_and_bt/src/main.c @@ -9,6 +9,14 @@ #include #include +#if NRF_CLOCK_HAS_HFCLK +#include +#elif NRF_CLOCK_HAS_XO +#include +#else +#error "HF clock not enabled" +#endif + #include LOG_MODULE_REGISTER(test); @@ -19,8 +27,10 @@ LOG_MODULE_REGISTER(test); static bool test_end; static const struct device *const entropy = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); -static const struct device *const clock_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock); -static struct device *hf_dev; +static const struct device *const clock_dev = DEVICE_DT_GET_ONE( + COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); static struct onoff_client cli; static uint32_t iteration; @@ -29,11 +39,6 @@ static void *setup(void) zassert_true(device_is_ready(entropy)); zassert_true(device_is_ready(clock_dev)); - hf_dev = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), - (nordic_nrf_clock_hfclk), - (nordic_nrf_clock_xo))); - zassert_true(hf_dev); - return NULL; } @@ -65,20 +70,21 @@ static void bt_timeout_handler(struct k_timer *timer) K_TIMER_DEFINE(timer1, bt_timeout_handler, NULL); -static void check_hf_status(const struct device *dev, bool exp_on, - bool sw_check) +static void check_hf_status(bool exp_on, bool sw_check) { nrf_clock_hfclk_t type; - nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_HFCLK, &type); + COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nrfx_clock_hfclk_running_check), + (nrfx_clock_xo_running_check))(&type); + zassert_equal(type, exp_on ? NRF_CLOCK_HFCLK_HIGH_ACCURACY : NRF_CLOCK_HFCLK_LOW_ACCURACY, "%d: Clock expected to be %s", iteration, exp_on ? "on" : "off"); if (sw_check) { - enum clock_control_status status = - clock_control_get_status(dev, CLOCK_CONTROL_NRF_SUBSYS_HF); + enum clock_control_status status = clock_control_get_status(clock_dev, NULL); zassert_equal(status, exp_on ? CLOCK_CONTROL_STATUS_ON : CLOCK_CONTROL_STATUS_OFF, @@ -117,16 +123,16 @@ ZTEST(nrf_onoff_and_bt, test_onoff_interrupted) backoff = 3 * rand; sys_notify_init_spinwait(&cli.notify); - err = nrf_clock_control_request(hf_dev, NULL, &cli); + err = nrf_clock_control_request(clock_dev, NULL, &cli); zassert_true(err >= 0); k_busy_wait(backoff); if (backoff > HF_STARTUP_TIME_US) { - check_hf_status(clock_dev, true, true); + check_hf_status(true, true); } - err = nrf_clock_control_cancel_or_release(hf_dev, NULL, &cli); + err = nrf_clock_control_cancel_or_release(clock_dev, NULL, &cli); zassert_true(err >= 0); elapsed = k_uptime_get() - start_time; @@ -138,7 +144,7 @@ ZTEST(nrf_onoff_and_bt, test_onoff_interrupted) test_end = true; k_msleep(100); - check_hf_status(clock_dev, false, true); + check_hf_status(false, true); } static void onoff_timeout_handler(struct k_timer *timer) @@ -209,7 +215,7 @@ ZTEST(nrf_onoff_and_bt, test_bt_interrupted) k_busy_wait(backoff); if (backoff > HF_STARTUP_TIME_US) { - check_hf_status(clock_dev, true, false); + check_hf_status(true, false); } z_nrf_clock_bt_ctlr_hf_release(); @@ -223,6 +229,6 @@ ZTEST(nrf_onoff_and_bt, test_bt_interrupted) test_end = true; k_msleep(100); - check_hf_status(clock_dev, false, true); + check_hf_status(false, true); } ZTEST_SUITE(nrf_onoff_and_bt, NULL, setup, NULL, NULL, NULL); diff --git a/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c b/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c index 382f9509f76e..9bc9ad3063e9 100644 --- a/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c +++ b/tests/drivers/clock_control/onoff/src/test_clock_control_onoff.c @@ -16,11 +16,13 @@ LOG_MODULE_REGISTER(test); static bool clock_is_off(void) { - const struct device *const clk = DEVICE_DT_GET_ONE(nordic_nrf_clock); + const struct device *const clk = DEVICE_DT_GET_ONE(COND_CODE_1((NRF_CLOCK_HAS_HFCLK), + (nordic_nrf_clock_hfclk), + (nordic_nrf_clock_xo))); zassert_true(device_is_ready(clk), "Device is not ready"); - return clock_control_get_status(clk, CLOCK_CONTROL_NRF_SUBSYS_HF) == + return clock_control_get_status(clk, NULL) == CLOCK_CONTROL_STATUS_OFF; }