Skip to content

Commit c863f9e

Browse files
mstasiaknordicnika-nordic
authored andcommitted
[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 c863f9e

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

drivers/clock_control/Kconfig.nrf

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,29 @@ 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+
depends on DT_HAS_NORDIC_NRF_HFXO_ENABLED
135+
depends on !TRUSTED_EXECUTION_NONSECURE
136+
select EXPERIMENTAL
137+
help
138+
Enables calibration of HFINT clock on every start of HFXO clock.
139+
140+
if CLOCK_CONTROL_NRF_HFINT_CALIBRATION
141+
142+
config CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD
143+
int "HFINT clock calibration period in milliseconds"
144+
default 60000
145+
help
146+
Periodically, HFINT clock calibration is performed.
147+
This includes requesting HFXO clock and starting actual calibration.
148+
Once the calibration is finished, the HFXO clock is released.
149+
Set to 0 to disable periodic calibration - in such case calibration
150+
will be done only when HFXO is started by the application itself.
151+
152+
endif # CLOCK_CONTROL_NRF_HFINT_CALIBRATION
153+
131154
choice CLOCK_CONTROL_NRF_ACCURACY_PPM
132155
prompt "32KHz clock accuracy"
133156
default CLOCK_CONTROL_NRF_K32SRC_500PPM if CLOCK_CONTROL_NRF_K32SRC_RC && SOC_COMPATIBLE_NRF52X

drivers/clock_control/clock_control_nrf.c

Lines changed: 86 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_PERIOD
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,90 @@ static void set_on_state(uint32_t *flags)
172177
irq_unlock(key);
173178
}
174179

180+
#ifdef CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION
181+
182+
static void nrf54l_errata_30_workaround(void)
183+
{
184+
while (FIELD_GET(CLOCK_XO_STAT_STATE_Msk, NRF_CLOCK->XO.STAT) !=
185+
CLOCK_XO_STAT_STATE_Running) {
186+
}
187+
const uint32_t higher_bits = *((volatile uint32_t *)0x50120820UL) & 0xFFFFFFC0;
188+
*((volatile uint32_t *)0x50120864UL) = 1 | BIT(31);
189+
*((volatile uint32_t *)0x50120848UL) = 1;
190+
uint32_t off_abs = 24;
191+
192+
while (off_abs >= 24) {
193+
*((volatile uint32_t *)0x50120844UL) = 1;
194+
while (((*((volatile uint32_t *)0x50120840UL)) & (1 << 16)) != 0) {
195+
}
196+
const uint32_t current_cal = *((volatile uint32_t *)0x50120820UL) & 0x3F;
197+
const uint32_t cal_result = *((volatile uint32_t *)0x50120840UL) & 0x7FF;
198+
int32_t off = 1024 - cal_result;
199+
200+
off_abs = (off < 0) ? -off : off;
201+
202+
if (off >= 24 && current_cal < 0x3F) {
203+
*((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal + 1);
204+
} else if (off <= -24 && current_cal > 0) {
205+
*((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal - 1);
206+
}
207+
}
208+
209+
*((volatile uint32_t *)0x50120848UL) = 0;
210+
*((volatile uint32_t *)0x50120864UL) = 0;
211+
}
212+
213+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD
214+
215+
static struct onoff_client hf_cal_cli;
216+
217+
static void calibration_finished_callback(struct onoff_manager *mgr,
218+
struct onoff_client *cli,
219+
uint32_t state,
220+
int res)
221+
{
222+
(void)onoff_cancel_or_release(mgr, cli);
223+
}
224+
225+
static void calibration_handler(struct k_timer *timer)
226+
{
227+
nrf_clock_hfclk_t clk_src;
228+
229+
bool ret = nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &clk_src);
230+
231+
if (ret && (clk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY)) {
232+
return;
233+
}
234+
235+
sys_notify_init_callback(&hf_cal_cli.notify, calibration_finished_callback);
236+
(void)onoff_request(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF),
237+
&hf_cal_cli);
238+
}
239+
240+
static K_TIMER_DEFINE(calibration_timer, calibration_handler, NULL);
241+
242+
static int calibration_init(void)
243+
{
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+
253+
#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD */
254+
#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION */
255+
175256
static void clkstarted_handle(const struct device *dev,
176257
enum clock_control_nrf_type type)
177258
{
259+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION
260+
if (nrf54l_errata_30() && (type == CLOCK_CONTROL_NRF_TYPE_HFCLK)) {
261+
nrf54l_errata_30_workaround();
262+
}
263+
#endif
178264
struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type);
179265
clock_control_cb_t callback = sub_data->cb;
180266
void *user_data = sub_data->user_data;

0 commit comments

Comments
 (0)