From 7425be77ee0b9e75953bdeadac4ef119a6246ca6 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 8 Nov 2024 16:47:56 +0100 Subject: [PATCH 1/6] dts: bindings: misc: add nordic,nrf-bicr Add binding for the Nordic nRF BICR memory. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/misc/nordic,nrf-bicr.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 dts/bindings/misc/nordic,nrf-bicr.yaml diff --git a/dts/bindings/misc/nordic,nrf-bicr.yaml b/dts/bindings/misc/nordic,nrf-bicr.yaml new file mode 100644 index 0000000000000..f5c127e6cf126 --- /dev/null +++ b/dts/bindings/misc/nordic,nrf-bicr.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic BICR (Board Information Configuration Registers) + +compatible: "nordic,nrf-bicr" + +include: base.yaml + +properties: + reg: + required: true From 0f0e089c25439a7ef053fe61ec46151be36d1274 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 8 Nov 2024 16:48:25 +0100 Subject: [PATCH 2/6] dts: common: nordic: nrf54h20: define BICR node BICR (Board Information Configuration Registers) are located within the application UICR region (ref. MRAM mapping, table 38). Signed-off-by: Gerard Marull-Paretas --- dts/common/nordic/nrf54h20.dtsi | 8 ++++++++ soc/nordic/validate_base_addresses.c | 1 + 2 files changed, 9 insertions(+) diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index 085aba43c86d8..6f3748bc9ccb6 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -220,7 +220,15 @@ cpuapp_uicr: uicr@fff8000 { compatible = "nordic,nrf-uicr-v2"; reg = <0xfff8000 DT_SIZE_K(2)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xfff8000 DT_SIZE_K(2)>; domain = <2>; + + bicr: bicr@7b0 { + compatible = "nordic,nrf-bicr"; + reg = <0x7b0 48>; + }; }; cpurad_uicr: uicr@fffa000 { diff --git a/soc/nordic/validate_base_addresses.c b/soc/nordic/validate_base_addresses.c index f47c3dc456ed9..ef1dd19457894 100644 --- a/soc/nordic/validate_base_addresses.c +++ b/soc/nordic/validate_base_addresses.c @@ -330,6 +330,7 @@ CHECK_DT_REG(uart136, NRF_UARTE136); CHECK_DT_REG(uart137, NRF_UARTE137); CHECK_DT_REG(uicr, NRF_UICR); CHECK_DT_REG(cpuapp_uicr, NRF_APPLICATION_UICR); +CHECK_DT_REG(bicr, NRF_APPLICATION_BICR); CHECK_DT_REG(cpurad_uicr, NRF_RADIOCORE_UICR); CHECK_DT_REG(usbd, NRF_USBD); CHECK_DT_REG(usbhs, NRF_USBHS); From 21901ca3f1a535466a5b4023d66bf492d974d808 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 7 Nov 2024 15:08:48 +0100 Subject: [PATCH 3/6] drivers: clock_control: nrf54h-hfxo: use values from BICR The real, applicable and trusted values are the ones flashed into BICR. So, drop DT properties that replicate BICR and use runtime reads to BICR instead. Signed-off-by: Gerard Marull-Paretas --- .../nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi | 2 -- .../clock_control/clock_control_nrf2_hfxo.c | 18 +++++++++++++----- dts/bindings/clock/nordic,nrf54h-hfxo.yaml | 13 ------------- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi index 595307aec8c81..ee47f0242a738 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi @@ -11,8 +11,6 @@ &hfxo { status = "okay"; accuracy-ppm = <30>; - startup-time-us = <850>; - mode = "crystal"; }; &lfxo { diff --git a/drivers/clock_control/clock_control_nrf2_hfxo.c b/drivers/clock_control/clock_control_nrf2_hfxo.c index 21723716ea6f4..31693a89272dc 100644 --- a/drivers/clock_control/clock_control_nrf2_hfxo.c +++ b/drivers/clock_control/clock_control_nrf2_hfxo.c @@ -12,6 +12,7 @@ LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); #include +#include BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "multiple instances not supported"); @@ -24,14 +25,16 @@ struct dev_data_hfxo { #if defined(CONFIG_ZERO_LATENCY_IRQS) uint16_t request_count; #endif /* CONFIG_ZERO_LATENCY_IRQS */ + k_timeout_t start_up_time; }; struct dev_config_hfxo { uint32_t fixed_frequency; uint16_t fixed_accuracy; - k_timeout_t start_up_time; }; +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + #if defined(CONFIG_ZERO_LATENCY_IRQS) static uint32_t full_irq_lock(void) { @@ -114,8 +117,6 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) { struct dev_data_hfxo *dev_data = CONTAINER_OF(mgr, struct dev_data_hfxo, mgr); - const struct device *dev = DEVICE_DT_INST_GET(0); - const struct dev_config_hfxo *dev_config = dev->config; dev_data->notify = notify; request_hfxo(dev_data); @@ -124,7 +125,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) * unreliable. Hence the timer is used to simply wait the expected * start-up time. To be removed once the hardware is fixed. */ - k_timer_start(&dev_data->timer, dev_config->start_up_time, K_NO_WAIT); + k_timer_start(&dev_data->timer, dev_data->start_up_time, K_NO_WAIT); } static void stop_hfxo(struct dev_data_hfxo *dev_data) @@ -258,6 +259,7 @@ static int init_hfxo(const struct device *dev) .start = onoff_start_hfxo, .stop = onoff_stop_hfxo }; + uint32_t start_up_time; int rc; rc = onoff_manager_init(&dev_data->mgr, &transitions); @@ -265,6 +267,13 @@ static int init_hfxo(const struct device *dev) return rc; } + start_up_time = nrf_bicr_hfxo_startup_time_us_get(BICR); + if (start_up_time == NRF_BICR_HFXO_STARTUP_TIME_UNCONFIGURED) { + return -EINVAL; + } + + dev_data->start_up_time = K_USEC(start_up_time); + k_timer_init(&dev_data->timer, hfxo_start_up_timer_handler, NULL); return 0; @@ -286,7 +295,6 @@ static struct dev_data_hfxo data_hfxo; static const struct dev_config_hfxo config_hfxo = { .fixed_frequency = DT_INST_PROP(0, clock_frequency), .fixed_accuracy = DT_INST_PROP(0, accuracy_ppm), - .start_up_time = K_USEC(DT_INST_PROP(0, startup_time_us)), }; DEVICE_DT_INST_DEFINE(0, init_hfxo, NULL, diff --git a/dts/bindings/clock/nordic,nrf54h-hfxo.yaml b/dts/bindings/clock/nordic,nrf54h-hfxo.yaml index 1dab8b99cf868..26280e770315a 100644 --- a/dts/bindings/clock/nordic,nrf54h-hfxo.yaml +++ b/dts/bindings/clock/nordic,nrf54h-hfxo.yaml @@ -15,16 +15,3 @@ properties: type: int description: Clock accuracy in parts per million required: true - - startup-time-us: - type: int - description: Clock startup time in micro seconds - required: true - - mode: - type: string - description: HFXO operational mode - required: true - enum: - - "crystal" - - "external-square" From bb2e6d4f2e83ad80e299418a9883670e0de627ae Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 8 Nov 2024 17:03:50 +0100 Subject: [PATCH 4/6] drivers: clock_control: nrf54h-common: add utility to obtain LFOSC acc Add a utility function to obtain LFOSC accuracy in PPM from BICR. Signed-off-by: Gerard Marull-Paretas --- .../clock_control/clock_control_nrf2_common.c | 37 +++++++++++++++++++ .../clock_control/clock_control_nrf2_common.h | 10 +++++ 2 files changed, 47 insertions(+) diff --git a/drivers/clock_control/clock_control_nrf2_common.c b/drivers/clock_control/clock_control_nrf2_common.c index 7bf8576880ba9..e9fbe00e9101c 100644 --- a/drivers/clock_control/clock_control_nrf2_common.c +++ b/drivers/clock_control/clock_control_nrf2_common.c @@ -5,6 +5,7 @@ #include "clock_control_nrf2_common.h" #include +#include #include LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -19,6 +20,8 @@ LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); (idx * sizeof(array[0])) - \ offsetof(type, array[0])) +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + /* * Definition of `struct clock_config_generic`. * Used to access `clock_config_*` structures in a common way. @@ -83,6 +86,40 @@ static inline uint8_t get_index_of_highest_bit(uint32_t value) return value ? (uint8_t)(31 - __builtin_clz(value)) : 0; } +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; +} + int clock_config_init(void *clk_cfg, uint8_t onoff_cnt, k_work_handler_t update_work_handler) { struct clock_config_generic *cfg = clk_cfg; diff --git a/drivers/clock_control/clock_control_nrf2_common.h b/drivers/clock_control/clock_control_nrf2_common.h index 858698c38ea7e..1f08e5b090f87 100644 --- a/drivers/clock_control/clock_control_nrf2_common.h +++ b/drivers/clock_control/clock_control_nrf2_common.h @@ -36,6 +36,16 @@ struct clock_onoff { struct clock_onoff onoff[_onoff_cnt]; \ } +/** + * @brief Obtain LFOSC accuracy in ppm. + * + * @param[out] accuracy Accuracy in ppm. + * + * @retval 0 On success + * @retval -EINVAL If accuracy is not configured. + */ +int lfosc_get_accuracy(uint16_t *accuracy); + /** * @brief Initializes a clock configuration structure. * From 505aaec93434a9caed49f03b2a5ee656e8bdf44e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 7 Nov 2024 15:56:33 +0100 Subject: [PATCH 5/6] drivers: clock_control: nrf54h-lfclk: use values from BICR The real, applicable and trusted values are the ones flashed into BICR. So, drop DT properties that replicate BICR and use runtime reads to BICR instead. Signed-off-by: Gerard Marull-Paretas --- .../nrf54h20dk_nrf54h20-common.dtsi | 3 - .../clock_control/clock_control_nrf2_lfclk.c | 109 ++++++++++-------- dts/bindings/clock/nordic,nrf54h-lfxo.yaml | 19 --- 3 files changed, 64 insertions(+), 67 deletions(-) diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi index ee47f0242a738..0c5307c4c8c25 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi @@ -15,7 +15,4 @@ &lfxo { status = "okay"; - accuracy-ppm = <20>; - startup-time-us = <600000>; - mode = "crystal"; }; diff --git a/drivers/clock_control/clock_control_nrf2_lfclk.c b/drivers/clock_control/clock_control_nrf2_lfclk.c index a4261c18f475f..2cbef9b8bf094 100644 --- a/drivers/clock_control/clock_control_nrf2_lfclk.c +++ b/drivers/clock_control/clock_control_nrf2_lfclk.c @@ -8,6 +8,7 @@ #include "clock_control_nrf2_common.h" #include #include +#include #include #include @@ -16,30 +17,25 @@ 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_LFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, lfxo) #define LFCLK_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo) -#define LFCLK_HAS_LFXO DT_NODE_HAS_STATUS_OKAY(LFCLK_LFXO_NODE) - #define LFCLK_LFLPRC_ACCURACY DT_INST_PROP(0, lflprc_accuracy_ppm) #define LFCLK_LFRC_ACCURACY DT_INST_PROP(0, lfrc_accuracy_ppm) -#define LFCLK_LFXO_ACCURACY DT_PROP(LFCLK_LFXO_NODE, accuracy_ppm) #define LFCLK_HFXO_ACCURACY DT_PROP(LFCLK_HFXO_NODE, accuracy_ppm) -#if LFCLK_HAS_LFXO -#define LFCLK_MAX_ACCURACY LFCLK_LFXO_ACCURACY -#else -#define LFCLK_MAX_ACCURACY LFCLK_HFXO_ACCURACY -#endif +#define LFCLK_MAX_OPTS 5 +#define LFCLK_DEF_OPTS 3 #define NRFS_CLOCK_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_NRFS_CLOCK_TIMEOUT_MS) +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + /* Clock options sorted from lowest to highest accuracy/precision */ -static const struct clock_options { +static struct clock_options { uint16_t accuracy : 15; uint16_t precision : 1; nrfs_clock_src_t src; -} clock_options[] = { +} clock_options[LFCLK_MAX_OPTS] = { { .accuracy = LFCLK_LFLPRC_ACCURACY, .precision = 0, @@ -56,43 +52,13 @@ static const struct clock_options { .precision = 1, .src = NRFS_CLOCK_SRC_LFCLK_SYNTH, }, -#if LFCLK_HAS_LFXO -#if DT_ENUM_HAS_VALUE(LFCLK_LFXO_NODE, mode, crystal) - { - .accuracy = LFCLK_LFXO_ACCURACY, - .src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE, - }, - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 1, - .src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP, - }, -#elif DT_ENUM_HAS_VALUE(LFCLK_LFXO_NODE, mode, external_sine) - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 0, - .src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE, - }, - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 1, - .src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP, - }, -#elif DT_ENUM_HAS_VALUE(LFCLK_LFXO_NODE, mode, external_square) - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 0, - .src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE, - }, -#else -#error "unsupported LFXO mode" -#endif -#endif }; 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; }; struct lfclk_dev_config { @@ -156,10 +122,10 @@ static struct onoff_manager *lfclk_find_mgr(const struct device *dev, } accuracy = spec->accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX - ? LFCLK_MAX_ACCURACY + ? dev_data->max_accuracy : spec->accuracy; - for (int i = 0; i < ARRAY_SIZE(clock_options); ++i) { + for (int i = 0; i < dev_data->clock_options_cnt; ++i) { if ((accuracy && accuracy < clock_options[i].accuracy) || spec->precision > clock_options[i].precision) { @@ -227,6 +193,7 @@ static int api_get_rate_lfclk(const struct device *dev, 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); @@ -234,6 +201,58 @@ static int lfclk_init(const struct device *dev) 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 - 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_PIERCE; + + clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 1].precision = 1; + clock_options[LFCLK_MAX_OPTS - 1].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 - 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_SINE; + + clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 1].precision = 1; + clock_options[LFCLK_MAX_OPTS - 1].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; + } + } + k_timer_init(&dev_data->timer, lfclk_update_timeout_handler, NULL); return clock_config_init(&dev_data->clk_cfg, diff --git a/dts/bindings/clock/nordic,nrf54h-lfxo.yaml b/dts/bindings/clock/nordic,nrf54h-lfxo.yaml index 3a85f27972d82..705c2483ecd12 100644 --- a/dts/bindings/clock/nordic,nrf54h-lfxo.yaml +++ b/dts/bindings/clock/nordic,nrf54h-lfxo.yaml @@ -10,22 +10,3 @@ include: fixed-clock.yaml properties: clock-frequency: const: 32768 - - accuracy-ppm: - type: int - description: Clock accuracy in parts per million - required: true - - startup-time-us: - type: int - description: Clock startup time in micro seconds - required: true - - mode: - type: string - description: LFXO operational mode - required: true - enum: - - "crystal" - - "external-sine" - - "external-square" From bf9bb1666d080a2808d87680b83817aef37e97d0 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 8 Nov 2024 17:05:09 +0100 Subject: [PATCH 6/6] drivers: clock_control: nrf54h-fll16m: use values from BICR The real, applicable and trusted values are the ones flashed into BICR. So, drop DT properties that replicate BICR and use runtime reads to BICR instead. Signed-off-by: Gerard Marull-Paretas --- .../clock_control/clock_control_nrf2_fll16m.c | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/clock_control/clock_control_nrf2_fll16m.c b/drivers/clock_control/clock_control_nrf2_fll16m.c index 1637284b3226c..cbec791aa77c6 100644 --- a/drivers/clock_control/clock_control_nrf2_fll16m.c +++ b/drivers/clock_control/clock_control_nrf2_fll16m.c @@ -8,7 +8,9 @@ #include "clock_control_nrf2_common.h" #include #include + #include +#include #include LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -23,26 +25,17 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, #define FLL16M_MODE_BYPASS 2 #define FLL16M_MODE_DEFAULT FLL16M_MODE_OPEN_LOOP -#define FLL16M_LFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, lfxo) #define FLL16M_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo) -#define FLL16M_HAS_LFXO DT_NODE_HAS_STATUS_OKAY(FLL16M_LFXO_NODE) - -#define FLL16M_LFXO_ACCURACY DT_PROP(FLL16M_LFXO_NODE, accuracy_ppm) #define FLL16M_HFXO_ACCURACY DT_PROP(FLL16M_HFXO_NODE, accuracy_ppm) #define FLL16M_OPEN_LOOP_ACCURACY DT_INST_PROP(0, open_loop_accuracy_ppm) #define FLL16M_CLOSED_LOOP_BASE_ACCURACY DT_INST_PROP(0, closed_loop_base_accuracy_ppm) #define FLL16M_MAX_ACCURACY FLL16M_HFXO_ACCURACY -/* Closed-loop mode uses LFXO as source if present, HFXO otherwise */ -#if FLL16M_HAS_LFXO -#define FLL16M_CLOSED_LOOP_ACCURACY (FLL16M_CLOSED_LOOP_BASE_ACCURACY + FLL16M_LFXO_ACCURACY) -#else -#define FLL16M_CLOSED_LOOP_ACCURACY (FLL16M_CLOSED_LOOP_BASE_ACCURACY + FLL16M_HFXO_ACCURACY) -#endif +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) /* Clock options sorted from lowest to highest accuracy */ -static const struct clock_options { +static struct clock_options { uint16_t accuracy; uint8_t mode; } clock_options[] = { @@ -51,7 +44,6 @@ static const struct clock_options { .mode = FLL16M_MODE_OPEN_LOOP, }, { - .accuracy = FLL16M_CLOSED_LOOP_ACCURACY, .mode = FLL16M_MODE_CLOSED_LOOP, }, { @@ -233,6 +225,27 @@ static int api_get_rate_fll16m(const struct device *dev, static int fll16m_init(const struct device *dev) { struct fll16m_dev_data *dev_data = dev->data; + nrf_bicr_lfosc_mode_t lfosc_mode; + + clock_options[1].accuracy = FLL16M_CLOSED_LOOP_BASE_ACCURACY; + + /* Closed-loop mode uses LFXO as source if present, HFXO otherwise */ + lfosc_mode = nrf_bicr_lfosc_mode_get(BICR); + + if (lfosc_mode != NRF_BICR_LFOSC_MODE_UNCONFIGURED && + lfosc_mode != NRF_BICR_LFOSC_MODE_DISABLED) { + int ret; + uint16_t accuracy; + + ret = lfosc_get_accuracy(&accuracy); + if (ret < 0) { + return ret; + } + + clock_options[1].accuracy += accuracy; + } else { + clock_options[1].accuracy += FLL16M_HFXO_ACCURACY; + } return clock_config_init(&dev_data->clk_cfg, ARRAY_SIZE(dev_data->clk_cfg.onoff),