From b35cb6cdf390db82d45be1d659d78253272532c1 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 14 Nov 2025 10:45:32 +0100 Subject: [PATCH] [nrf fromlist] drivers: clock_control nrf_lfclk: patch clock option order The clock options used within the driver are supposed to be ordered from lowest to highest power consumption, so the lowest/default option is the most power efficient. The order was reversed to make the init code of the lfclk a bit simpler, and this was accounted for in the clock option lookup function. However, the common nrf clock control request/release feature would request the lowest index, not the lowest clock option, so the lfclk would default to its highest power consumption mode. The clock option init and lookup has been refactored to be sorted from lowest to highest power consumption, and comments have been adjusted accordingly. Upstream PR #: 99382 Signed-off-by: Bjarki Arge Andreasen --- .../clock_control/clock_control_nrf_lfclk.c | 104 +++++++++--------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/drivers/clock_control/clock_control_nrf_lfclk.c b/drivers/clock_control/clock_control_nrf_lfclk.c index 9551fb4e6361..dbf7f66e2e25 100644 --- a/drivers/clock_control/clock_control_nrf_lfclk.c +++ b/drivers/clock_control/clock_control_nrf_lfclk.c @@ -25,38 +25,25 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, #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_NRF_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 +/* + * Clock options sorted from lowest to highest power consumption. If clock option + * is not available it is not included. + * - External sine or square wave + * - XTAL low precision + * - XTAL high precision * - 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 + * - Clock synthesized from a high frequency clock */ 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 */ -}; +} clock_options[LFCLK_MAX_OPTS]; struct lfclk_dev_data { STRUCT_CLOCK_CONFIG(lfclk, ARRAY_SIZE(clock_options)) clk_cfg; @@ -161,7 +148,7 @@ static int lfclk_resolve_spec_to_idx(const struct device *dev, ? dev_data->max_accuracy : req_spec->accuracy; - for (int i = dev_data->clock_options_cnt - 1; i >= 0; --i) { + for (int i = 0; i < dev_data->clock_options_cnt; 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. @@ -331,15 +318,17 @@ 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; + int ret; + nrf_bicr_lfosc_mode_t lfosc_mode; + struct clock_options *clock_option; res = nrfs_clock_init(clock_evt_handler); if (res != NRFS_SUCCESS) { return -EIO; } - dev_data->clock_options_cnt = LFCLK_DEF_OPTS; + dev_data->clock_options_cnt = 0; lfosc_mode = nrf_bicr_lfosc_mode_get(BICR); @@ -347,8 +336,6 @@ static int lfclk_init(const struct device *dev) 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"); @@ -357,34 +344,41 @@ static int lfclk_init(const struct device *dev) 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; + clock_option = &clock_options[dev_data->clock_options_cnt]; + clock_option->accuracy = dev_data->max_accuracy; + clock_option->precision = 0; + clock_option->src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE; + dev_data->clock_options_cnt++; + + clock_option = &clock_options[dev_data->clock_options_cnt]; + clock_option->accuracy = dev_data->max_accuracy; + clock_option->precision = 1; + clock_option->src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP; + dev_data->clock_options_cnt++; 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; + case NRF_BICR_LFOSC_MODE_EXTSINE: + clock_option = &clock_options[dev_data->clock_options_cnt]; + clock_option->accuracy = dev_data->max_accuracy; + clock_option->precision = 0; + clock_option->src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE; + dev_data->clock_options_cnt++; + + clock_option = &clock_options[dev_data->clock_options_cnt]; + clock_option->accuracy = dev_data->max_accuracy; + clock_option->precision = 1; + clock_option->src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP; + dev_data->clock_options_cnt++; 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; + case NRF_BICR_LFOSC_MODE_EXTSQUARE: + clock_option = &clock_options[dev_data->clock_options_cnt]; + clock_option->accuracy = dev_data->max_accuracy; + clock_option->precision = 0; + clock_option->src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE; + dev_data->clock_options_cnt++; break; + default: LOG_ERR("Unexpected LFOSC mode"); return -EINVAL; @@ -398,6 +392,18 @@ static int lfclk_init(const struct device *dev) } } + clock_option = &clock_options[dev_data->clock_options_cnt]; + clock_option->accuracy = LFCLK_LFRC_ACCURACY; + clock_option->precision = 0; + clock_option->src = NRFS_CLOCK_SRC_LFCLK_LFRC; + dev_data->clock_options_cnt++; + + clock_option = &clock_options[dev_data->clock_options_cnt]; + clock_option->accuracy = LFCLK_HFXO_ACCURACY; + clock_option->precision = 1; + clock_option->src = NRFS_CLOCK_SRC_LFCLK_SYNTH; + dev_data->clock_options_cnt++; + 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");