Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: clock_control: nrf54h: obtain oscillator parameters from BICR #81122

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@
&hfxo {
status = "okay";
accuracy-ppm = <30>;
startup-time-us = <850>;
mode = "crystal";
};

&lfxo {
status = "okay";
accuracy-ppm = <20>;
startup-time-us = <600000>;
mode = "crystal";
};
37 changes: 37 additions & 0 deletions drivers/clock_control/clock_control_nrf2_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include "clock_control_nrf2_common.h"
#include <hal/nrf_bicr.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
Expand All @@ -24,6 +25,8 @@ LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
*/
STRUCT_CLOCK_CONFIG(generic, ONOFF_CNT_MAX);

#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr))

static void update_config(struct clock_config_generic *cfg)
{
atomic_val_t prev_flags = atomic_or(&cfg->flags, FLAG_UPDATE_NEEDED);
Expand Down Expand Up @@ -75,6 +78,40 @@ static inline uint8_t get_index_of_highest_bit(uint32_t value)
return value ? (uint8_t)(31 - __builtin_clz(value)) : 0;
}

int lfosc_get_accuracy(uint16_t *accuracy)
{
switch (nrf_bicr_lfosc_accuracy_get(BICR)) {
case NRF_BICR_LFOSC_ACCURACY_500PPM:
*accuracy = 500U;
break;
case NRF_BICR_LFOSC_ACCURACY_250PPM:
*accuracy = 250U;
break;
case NRF_BICR_LFOSC_ACCURACY_150PPM:
*accuracy = 150U;
break;
case NRF_BICR_LFOSC_ACCURACY_100PPM:
*accuracy = 100U;
break;
case NRF_BICR_LFOSC_ACCURACY_75PPM:
*accuracy = 75U;
break;
case NRF_BICR_LFOSC_ACCURACY_50PPM:
*accuracy = 50U;
break;
case NRF_BICR_LFOSC_ACCURACY_30PPM:
*accuracy = 30U;
break;
case NRF_BICR_LFOSC_ACCURACY_20PPM:
*accuracy = 20U;
break;
default:
return -EINVAL;
}

return 0;
}

int clock_config_init(void *clk_cfg, uint8_t onoff_cnt, k_work_handler_t update_work_handler)
{
struct clock_config_generic *cfg = clk_cfg;
Expand Down
10 changes: 10 additions & 0 deletions drivers/clock_control/clock_control_nrf2_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ struct clock_onoff {
struct clock_onoff onoff[_onoff_cnt]; \
}

/**
* @brief Obtain LFOSC accuracy in ppm.
*
* @param[out] accuracy Accuracy in ppm.
*
* @retval 0 On success
* @retval -EINVAL If accuracy is not configured.
*/
int lfosc_get_accuracy(uint16_t *accuracy);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to add a prefix to this function, considering it's available in the global scope


/**
* @brief Initializes a clock configuration structure.
*
Expand Down
37 changes: 25 additions & 12 deletions drivers/clock_control/clock_control_nrf2_fll16m.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#include "clock_control_nrf2_common.h"
#include <zephyr/devicetree.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>

#include <soc_lrcconf.h>
#include <hal/nrf_bicr.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
Expand All @@ -23,26 +25,17 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
#define FLL16M_MODE_BYPASS 2
#define FLL16M_MODE_DEFAULT FLL16M_MODE_OPEN_LOOP

#define FLL16M_LFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, lfxo)
#define FLL16M_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo)

#define FLL16M_HAS_LFXO DT_NODE_HAS_STATUS_OKAY(FLL16M_LFXO_NODE)

#define FLL16M_LFXO_ACCURACY DT_PROP(FLL16M_LFXO_NODE, accuracy_ppm)
#define FLL16M_HFXO_ACCURACY DT_PROP(FLL16M_HFXO_NODE, accuracy_ppm)
hubertmis marked this conversation as resolved.
Show resolved Hide resolved
#define FLL16M_OPEN_LOOP_ACCURACY DT_INST_PROP(0, open_loop_accuracy_ppm)
#define FLL16M_CLOSED_LOOP_BASE_ACCURACY DT_INST_PROP(0, closed_loop_base_accuracy_ppm)
#define FLL16M_MAX_ACCURACY FLL16M_HFXO_ACCURACY

/* Closed-loop mode uses LFXO as source if present, HFXO otherwise */
#if FLL16M_HAS_LFXO
#define FLL16M_CLOSED_LOOP_ACCURACY (FLL16M_CLOSED_LOOP_BASE_ACCURACY + FLL16M_LFXO_ACCURACY)
#else
#define FLL16M_CLOSED_LOOP_ACCURACY (FLL16M_CLOSED_LOOP_BASE_ACCURACY + FLL16M_HFXO_ACCURACY)
#endif
#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr))

/* Clock options sorted from lowest to highest accuracy */
static const struct clock_options {
static struct clock_options {
uint16_t accuracy;
uint8_t mode;
} clock_options[] = {
Expand All @@ -51,7 +44,6 @@ static const struct clock_options {
.mode = FLL16M_MODE_OPEN_LOOP,
},
{
.accuracy = FLL16M_CLOSED_LOOP_ACCURACY,
.mode = FLL16M_MODE_CLOSED_LOOP,
},
hubertmis marked this conversation as resolved.
Show resolved Hide resolved
{
Expand Down Expand Up @@ -233,6 +225,27 @@ static int api_get_rate_fll16m(const struct device *dev,
static int fll16m_init(const struct device *dev)
{
struct fll16m_dev_data *dev_data = dev->data;
nrf_bicr_lfosc_mode_t lfosc_mode;

clock_options[1].accuracy = FLL16M_CLOSED_LOOP_BASE_ACCURACY;

/* Closed-loop mode uses LFXO as source if present, HFXO otherwise */
lfosc_mode = nrf_bicr_lfosc_mode_get(BICR);

if (lfosc_mode != NRF_BICR_LFOSC_MODE_UNCONFIGURED &&
lfosc_mode != NRF_BICR_LFOSC_MODE_DISABLED) {
int ret;
uint16_t accuracy;

ret = lfosc_get_accuracy(&accuracy);
if (ret < 0) {
return ret;
}

clock_options[1].accuracy += accuracy;
} else {
clock_options[1].accuracy += FLL16M_HFXO_ACCURACY;
}

return clock_config_init(&dev_data->clk_cfg,
ARRAY_SIZE(dev_data->clk_cfg.onoff),
Expand Down
18 changes: 13 additions & 5 deletions drivers/clock_control/clock_control_nrf2_hfxo.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);

#include <soc_lrcconf.h>
#include <hal/nrf_bicr.h>

BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
"multiple instances not supported");
Expand All @@ -21,14 +22,16 @@ struct dev_data_hfxo {
onoff_notify_fn notify;
struct k_timer timer;
sys_snode_t hfxo_node;
k_timeout_t start_up_time;
};

struct dev_config_hfxo {
uint32_t fixed_frequency;
uint16_t fixed_accuracy;
k_timeout_t start_up_time;
};

#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr))

static void hfxo_start_up_timer_handler(struct k_timer *timer)
{
struct dev_data_hfxo *dev_data =
Expand All @@ -52,8 +55,6 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
{
struct dev_data_hfxo *dev_data =
CONTAINER_OF(mgr, struct dev_data_hfxo, mgr);
const struct device *dev = DEVICE_DT_INST_GET(0);
const struct dev_config_hfxo *dev_config = dev->config;

dev_data->notify = notify;

Expand All @@ -65,7 +66,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
* unreliable. Hence the timer is used to simply wait the expected
* start-up time. To be removed once the hardware is fixed.
*/
k_timer_start(&dev_data->timer, dev_config->start_up_time, K_NO_WAIT);
k_timer_start(&dev_data->timer, dev_data->start_up_time, K_NO_WAIT);
}

static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
Expand Down Expand Up @@ -159,13 +160,21 @@ static int init_hfxo(const struct device *dev)
.start = onoff_start_hfxo,
.stop = onoff_stop_hfxo
};
uint32_t start_up_time;
int rc;

rc = onoff_manager_init(&dev_data->mgr, &transitions);
if (rc < 0) {
return rc;
}

start_up_time = nrf_bicr_hfxo_startup_time_us_get(BICR);
if (start_up_time == NRF_BICR_HFXO_STARTUP_TIME_UNCONFIGURED) {
return -EINVAL;
}

dev_data->start_up_time = K_USEC(start_up_time);

k_timer_init(&dev_data->timer, hfxo_start_up_timer_handler, NULL);

return 0;
Expand All @@ -187,7 +196,6 @@ static struct dev_data_hfxo data_hfxo;
static const struct dev_config_hfxo config_hfxo = {
.fixed_frequency = DT_INST_PROP(0, clock_frequency),
.fixed_accuracy = DT_INST_PROP(0, accuracy_ppm),
.start_up_time = K_USEC(DT_INST_PROP(0, startup_time_us)),
};

DEVICE_DT_INST_DEFINE(0, init_hfxo, NULL,
Expand Down
Loading
Loading