Skip to content

Commit

Permalink
drivers: clock_control: nrf54h-lfclk: use values from BICR
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
gmarull committed Nov 8, 2024
1 parent 4b8535b commit 9654417
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 61 deletions.
3 changes: 0 additions & 3 deletions boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,4 @@

&lfxo {
status = "okay";
accuracy-ppm = <20>;
startup-time-us = <600000>;
mode = "crystal";
};
127 changes: 88 additions & 39 deletions drivers/clock_control/clock_control_nrf2_lfclk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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;

Check notice on line 130 in drivers/clock_control/clock_control_nrf2_lfclk.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/clock_control/clock_control_nrf2_lfclk.c:130 - accuracy = spec->accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX - ? dev_data->max_accuracy - : spec->accuracy; + accuracy = spec->accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX ? 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) {
Expand Down Expand Up @@ -224,6 +193,41 @@ static int api_get_rate_lfclk(const struct device *dev,
return 0;
}

static int lfosc_get_accuracy(uint16_t *accuracy)
{
switch (FIELD_GET(NRF_APPLICATION_BICR_NS->LFOSC.LFXOCONFIG,
BICR_LFOSC_LFXOCONFIG_ACCURACY_Msk)) {
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;
Expand All @@ -234,6 +238,51 @@ 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 (FIELD_GET(NRF_APPLICATION_BICR_NS->LFOSC.LFXOCONFIG,
BICR_LFOSC_LFXOCONFIG_MODE_Msk)) {
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,
Expand Down
19 changes: 0 additions & 19 deletions dts/bindings/clock/nordic,nrf54h-lfxo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"

0 comments on commit 9654417

Please sign in to comment.