From 83938e65cba6842c253c1b7741d33d669548bdf4 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 00000000000000..f5c127e6cf1260 --- /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 08f6abad8ddea830b6ff4ed7ae663f3e97a0b16f 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 417eb4670ed85a..38658f2a69b766 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -218,7 +218,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 f47c3dc456ed9b..ef1dd194578947 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 74a8fcbd38aa0cc3ce48eebc0b357cc2c7c14ac6 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 595307aec8c81f..ee47f0242a7388 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 977c0aaa0d6804..e7107f8d9cd80e 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"); @@ -21,14 +22,16 @@ struct dev_data_hfxo { onoff_notify_fn notify; struct k_timer timer; sys_snode_t hfxo_node; + 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)) + static void hfxo_start_up_timer_handler(struct k_timer *timer) { struct dev_data_hfxo *dev_data = @@ -52,8 +55,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; @@ -65,7 +66,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 onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) @@ -159,6 +160,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); @@ -166,6 +168,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; @@ -187,7 +196,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 1dab8b99cf8680..26280e770315ad 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 e12a2d6f7c837e4c11bd062113a4066639bbf021 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 f3b21a5dd1fbe0..3c40a83aa62c0e 100644 --- a/drivers/clock_control/clock_control_nrf2_common.c +++ b/drivers/clock_control/clock_control_nrf2_common.c @@ -4,6 +4,7 @@ */ #include "clock_control_nrf2_common.h" +#include #include LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -24,6 +25,8 @@ LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); */ STRUCT_CLOCK_CONFIG(generic, ONOFF_CNT_MAX); +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + static void update_config(struct clock_config_generic *cfg) { atomic_val_t prev_flags = atomic_or(&cfg->flags, FLAG_UPDATE_NEEDED); @@ -75,6 +78,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 858698c38ea7ea..1f08e5b090f875 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 e3bdbf044919640b2f7220b1e83efafcfdae0488 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 ee47f0242a7388..0c5307c4c8c25f 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 36b8e2472977b9..fc208b913c3dbf 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 3a85f27972d82c..705c2483ecd124 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 918d207b586386f040f9ca0d72b2338cb995008e 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 613e433e527492..6aa38cbbff3167 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),