diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi index ee47f0242a7388e..0c5307c4c8c25f7 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 36b8e2472977b93..1de71016931b95c 100644 --- a/drivers/clock_control/clock_control_nrf2_lfclk.c +++ b/drivers/clock_control/clock_control_nrf2_lfclk.c @@ -23,23 +23,22 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, #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 +#define LFCLK_MAX_OPTS 5 #else -#define LFCLK_MAX_ACCURACY LFCLK_HFXO_ACCURACY +#define LFCLK_MAX_OPTS 3 #endif #define NRFS_CLOCK_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_NRFS_CLOCK_TIMEOUT_MS) /* 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 +55,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 +125,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) { @@ -224,6 +193,40 @@ static int api_get_rate_lfclk(const struct device *dev, return 0; } +static int lfosc_get_accuracy(uint16_t *accuracy) +{ + switch (NRF_APPLICATION_BICR_NS->LFOSC.ACCURACY) { + case BICR_LFOSC_LFXOCONFIG_ACCURACY_500ppm: + *accuracy = 500U; + break; + case BICR_LFOSC_LFXOCONFIG_ACCURACY_250ppm: + *accuracy = 250U; + break; + case BICR_LFOSC_LFXOCONFIG_ACCURACY_150ppm: + *accuracy = 150U; + break; + case BICR_LFOSC_LFXOCONFIG_ACCURACY_100ppm: + *accuracy = 100U; + break; + case BICR_LFOSC_LFXOCONFIG_ACCURACY_75ppm: + *accuracy = 75U; + break; + case BICR_LFOSC_LFXOCONFIG_ACCURACY_50ppm: + *accuracy = 50U; + break; + case BICR_LFOSC_LFXOCONFIG_ACCURACY_30ppm: + *accuracy = 30U; + break; + case BICR_LFOSC_LFXOCONFIG_ACCURACY_20ppm: + *accuracy = 20U; + break; + default: + return -EINVAL; + } + + return 0; +} + static int lfclk_init(const struct device *dev) { struct lfclk_dev_data *dev_data = dev->data; @@ -234,6 +237,50 @@ static int lfclk_init(const struct device *dev) return -EIO; } + dev_data->clock_options_cnt = LFCLK_MAX_OPTS; + +#if LFCLK_HAS_LFXO + int ret; + + ret = lfosc_get_accuracy(&dev_data->max_accuracy); + if (ret < 0) { + return ret; + } + + switch (NRF_APPLICATION_BICR_NS->LFOSC.MODE) { + case BICR_LFOSC_LFXOCONFIG_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; + break; + case BICR_LFOSC_LFXOCONFIG_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; + break; + case BICR_LFOSC_LFXOCONFIG_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; + + /* last option not used */ + dev_data->clock_options_cnt--; + break; + default: + return -EINVAL; + } +#else + dev_data->max_accuracy = LFCLK_HFXO_ACCURACY; +#endif + 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 3a85f27972d82cf..705c2483ecd124a 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"