Skip to content

Commit 441b41b

Browse files
[nrf fromlist] drivers: clock_control: nrf: Apply fix for nRF54L anomaly 30.
Applied fix for nRF54L anomaly 30, which requires a periodic calibration of high-frequency clock. Upstream PR #: 88112 Signed-off-by: Michał Stasiak <[email protected]>
1 parent e48bca4 commit 441b41b

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

drivers/clock_control/Kconfig.nrf

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,26 @@ config CLOCK_CONTROL_NRF_USES_TEMP_SENSOR
128128
endif # CLOCK_CONTROL_NRF_DRIVER_CALIBRATION
129129
endif # CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION
130130

131+
config CLOCK_CONTROL_NRF_HFINT_CALIBRATION
132+
bool "HFINT clock calibration"
133+
depends on SOC_NRF54L05 || SOC_NRF54L10 || SOC_NRF54L15
134+
help
135+
Enables periodic calibration of high-frequency clock. Calibration
136+
is experimental.
137+
138+
if CLOCK_CONTROL_NRF_HFINT_CALIBRATION
139+
140+
config CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD
141+
int "HFINT clock calibration period in milliseconds"
142+
default 60000
143+
help
144+
Periodically, high-frequency internal clock calibration is
145+
performed. This includes requesting high-frequency clock and
146+
starting actual calibration. Once calibration is finished,
147+
the clock is released.
148+
149+
endif # CLOCK_CONTROL_NRF_HFINT_CALIBRATION
150+
131151
choice CLOCK_CONTROL_NRF_ACCURACY_PPM
132152
prompt "32KHz clock accuracy"
133153
default CLOCK_CONTROL_NRF_K32SRC_500PPM if CLOCK_CONTROL_NRF_K32SRC_RC && SOC_COMPATIBLE_NRF52X

drivers/clock_control/clock_control_nrf.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <zephyr/logging/log.h>
1515
#include <zephyr/shell/shell.h>
1616
#include <zephyr/irq.h>
17+
#include <nrf_erratas.h>
1718

1819
LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
1920

@@ -84,6 +85,10 @@ static uint64_t hf_stop_tstamp;
8485
static struct onoff_client lfsynth_cli;
8586
#endif
8687

88+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION
89+
static struct onoff_client hf_cal_cli;
90+
#endif
91+
8792
static struct nrf_clock_control_sub_data *get_sub_data(const struct device *dev,
8893
enum clock_control_nrf_type type)
8994
{
@@ -172,9 +177,88 @@ static void set_on_state(uint32_t *flags)
172177
irq_unlock(key);
173178
}
174179

180+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION
181+
182+
static void calibration_finished_callback(struct onoff_manager *mgr,
183+
struct onoff_client *cli,
184+
uint32_t state,
185+
int res)
186+
{
187+
(void)onoff_cancel_or_release(mgr, cli);
188+
}
189+
190+
static void calibration_handler(struct k_timer *timer)
191+
{
192+
nrf_clock_hfclk_t clk_src;
193+
194+
bool ret = nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &clk_src);
195+
196+
if (ret && (clk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY)) {
197+
return;
198+
}
199+
200+
(void)onoff_request(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF),
201+
&hf_cal_cli);
202+
}
203+
204+
static K_TIMER_DEFINE(calibration_timer, calibration_handler, NULL);
205+
206+
static void nrf_errata_30_workaround(void)
207+
{
208+
if (!nrf54l_errata_30()) {
209+
return;
210+
}
211+
212+
while ((NRF_CLOCK->XO.STAT & CLOCK_XO_STAT_STATE_Msk) != CLOCK_XO_STAT_STATE_Running
213+
<< CLOCK_XO_STAT_STATE_Pos) {
214+
}
215+
const uint32_t higher_bits = *((volatile uint32_t *)0x50120820UL) & 0xFFFFFFC0;
216+
*((volatile uint32_t *)0x50120864UL) = 1 | (1 << 31);
217+
*((volatile uint32_t *)0x50120848UL) = 1;
218+
uint32_t off_abs = 24;
219+
220+
while (off_abs >= 24) {
221+
*((volatile uint32_t *)0x50120844UL) = 1;
222+
while (((*((volatile uint32_t *)0x50120840UL)) & (1 << 16)) != 0) {
223+
}
224+
const uint32_t current_cal = *((volatile uint32_t *)0x50120820UL) & 0x3F;
225+
const uint32_t cal_result = *((volatile uint32_t *)0x50120840UL) & 0x7FF;
226+
int32_t off = 1024 - cal_result;
227+
228+
off_abs = (off < 0) ? -off : off;
229+
230+
if (off >= 24 && current_cal < 0x3F) {
231+
*((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal + 1);
232+
} else if (off <= -24 && current_cal > 0) {
233+
*((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal - 1);
234+
}
235+
}
236+
237+
*((volatile uint32_t *)0x50120848UL) = 0;
238+
*((volatile uint32_t *)0x50120864UL) = 0;
239+
}
240+
241+
static int calibration_init(void)
242+
{
243+
sys_notify_init_callback(&hf_cal_cli.notify, calibration_finished_callback);
244+
k_timer_start(&calibration_timer,
245+
K_NO_WAIT,
246+
K_MSEC(CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD));
247+
248+
return 0;
249+
}
250+
251+
SYS_INIT(calibration_init, APPLICATION, 0);
252+
#endif
253+
175254
static void clkstarted_handle(const struct device *dev,
176255
enum clock_control_nrf_type type)
177256
{
257+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION
258+
if (type == CLOCK_CONTROL_NRF_TYPE_HFCLK) {
259+
nrf_errata_30_workaround();
260+
}
261+
#endif
178262
struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type);
179263
clock_control_cb_t callback = sub_data->cb;
180264
void *user_data = sub_data->user_data;

0 commit comments

Comments
 (0)