diff --git a/drivers/clock_control/clock_control_nrf2_lfclk.c b/drivers/clock_control/clock_control_nrf2_lfclk.c index 6be9deee657..da2bee72d2b 100644 --- a/drivers/clock_control/clock_control_nrf2_lfclk.c +++ b/drivers/clock_control/clock_control_nrf2_lfclk.c @@ -32,16 +32,25 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, #define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) -/* Clock options sorted from lowest to highest accuracy/precision */ +/* Clock options sorted from highest to lowest power consumption. + * - Clock synthesized from a high frequency clock + * - Internal RC oscillator + * - Internal low power 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] = { { - .accuracy = LFCLK_LFLPRC_ACCURACY, - .precision = 0, - .src = NRFS_CLOCK_SRC_LFCLK_LFLPRC, + /* 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, @@ -50,10 +59,11 @@ static struct clock_options { }, { /* 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_LFLPRC_ACCURACY, + .precision = 0, + .src = NRFS_CLOCK_SRC_LFCLK_LFLPRC, }, + /* Remaining options are populated on lfclk_init */ }; struct lfclk_dev_data { @@ -125,10 +135,15 @@ static int lfclk_resolve_spec_to_idx(const struct device *dev, ? dev_data->max_accuracy : req_spec->accuracy; - for (int i = 0; i < dev_data->clock_options_cnt; ++i) { - if ((req_accuracy && - req_accuracy < clock_options[i].accuracy) || - req_spec->precision > clock_options[i].precision) { + 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; } @@ -316,24 +331,24 @@ static int lfclk_init(const struct device *dev) 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; + 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 - 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; + 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;