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 <gerard@teslabs.com>
This commit is contained in:
Gerard Marull-Paretas 2024-11-07 15:56:33 +01:00 committed by Benjamin Cabé
parent d5041aecec
commit f267c339f7
3 changed files with 64 additions and 67 deletions

View file

@ -15,7 +15,4 @@
&lfxo {
status = "okay";
accuracy-ppm = <20>;
startup-time-us = <600000>;
mode = "crystal";
};

View file

@ -8,6 +8,7 @@
#include "clock_control_nrf2_common.h"
#include <zephyr/devicetree.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <hal/nrf_bicr.h>
#include <nrfs_clock.h>
#include <zephyr/logging/log.h>
@ -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,

View file

@ -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"