Skip to content

Commit 7523156

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 7523156

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

drivers/clock_control/Kconfig.nrf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,27 @@ 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_HF_CALIBRATION
132+
bool "HF clock calibration"
133+
depends on SOC_NRF54L05 || SOC_NRF54L10 || SOC_NRF54L15
134+
default n
135+
help
136+
Enables periodic calibration of high-frequency clock. Calibration
137+
is experimental.
138+
139+
if CLOCK_CONTROL_NRF_HF_CALIBRATION
140+
141+
config CLOCK_CONTROL_NRF_HF_CALIBRATION_PERIOD
142+
int "HF clock calibration period in milliseconds"
143+
default 60000
144+
help
145+
Periodically, high-frequency clock calibration is performed.
146+
This includes requesting high-frequency clock and starting
147+
actual calibration. Once calibration is finished, the clock
148+
is released.
149+
150+
endif # CLOCK_CONTROL_NRF_HF_CALIBRATION
151+
131152
choice CLOCK_CONTROL_NRF_ACCURACY_PPM
132153
prompt "32KHz clock accuracy"
133154
default CLOCK_CONTROL_NRF_K32SRC_500PPM if CLOCK_CONTROL_NRF_K32SRC_RC && SOC_COMPATIBLE_NRF52X

drivers/clock_control/clock_control_nrf.c

Lines changed: 75 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,11 @@ static uint64_t hf_stop_tstamp;
8485
static struct onoff_client lfsynth_cli;
8586
#endif
8687

88+
#if CONFIG_CLOCK_CONTROL_NRF_HF_CALIBRATION
89+
static struct onoff_client hf_cal_cli;
90+
static K_SEM_DEFINE(cal_sem, 0, 1);
91+
#endif
92+
8793
static struct nrf_clock_control_sub_data *get_sub_data(const struct device *dev,
8894
enum clock_control_nrf_type type)
8995
{
@@ -172,9 +178,78 @@ static void set_on_state(uint32_t *flags)
172178
irq_unlock(key);
173179
}
174180

181+
#if CONFIG_CLOCK_CONTROL_NRF_HF_CALIBRATION
182+
183+
static void calibration_handler(struct k_timer *timer)
184+
{
185+
if (nrfx_clock_hfclk_is_running()) {
186+
return;
187+
}
188+
sys_notify_init_spinwait(&hf_cal_cli.notify);
189+
(void)onoff_request(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF),
190+
&hf_cal_cli);
191+
k_sem_take(&cal_sem, K_FOREVER);
192+
(void)onoff_cancel_or_release(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF),
193+
&hf_cal_cli);
194+
}
195+
196+
static K_TIMER_DEFINE(calibration_timer, calibration_handler, NULL);
197+
198+
static void nrf_errata_30_workaround(void)
199+
{
200+
if (!nrf54l_errata_30()) {
201+
return;
202+
}
203+
204+
while ((NRF_CLOCK->XO.STAT & CLOCK_XO_STAT_STATE_Msk) != CLOCK_XO_STAT_STATE_Running
205+
<< CLOCK_XO_STAT_STATE_Pos) {
206+
}
207+
const uint32_t higher_bits = *((volatile uint32_t *)0x50120820ul) & 0xFFFFFFC0;
208+
*((volatile uint32_t *)0x50120864ul) = 1 | (1 << 31);
209+
*((volatile uint32_t *)0x50120848ul) = 1;
210+
uint32_t off_abs = 24;
211+
212+
while (off_abs >= 24) {
213+
*((volatile uint32_t *)0x50120844ul) = 1;
214+
while (((*((volatile uint32_t *)0x50120840ul)) & (1 << 16)) != 0) {
215+
}
216+
const uint32_t current_trim = *((volatile uint32_t *)0x50120820ul) & 0x3F;
217+
const uint32_t meetering_result = *((volatile uint32_t *)0x50120840ul) & 0x7FF;
218+
int32_t off = 1024 - meetering_result;
219+
220+
off_abs = (off < 0) ? -off : off;
221+
if (off >= 24 && current_trim < 0x3F) {
222+
*((volatile uint32_t *)0x50120820ul) = higher_bits | (current_trim + 1);
223+
} else if (off <= -24 && current_trim > 0) {
224+
*((volatile uint32_t *)0x50120820ul) = higher_bits | (current_trim - 1);
225+
}
226+
}
227+
228+
*((volatile uint32_t *)0x50120848ul) = 0;
229+
230+
k_sem_give(&cal_sem);
231+
}
232+
233+
static int calibration_init(void)
234+
{
235+
k_timer_start(&calibration_timer,
236+
K_NO_WAIT,
237+
K_MSEC(CONFIG_CLOCK_CONTROL_NRF_HF_CALIBRATION_PERIOD));
238+
239+
return 0;
240+
}
241+
242+
SYS_INIT(calibration_init, APPLICATION, 0);
243+
#endif
244+
175245
static void clkstarted_handle(const struct device *dev,
176246
enum clock_control_nrf_type type)
177247
{
248+
#if CONFIG_CLOCK_CONTROL_NRF_HF_CALIBRATION
249+
if (type == CLOCK_CONTROL_NRF_TYPE_HFCLK) {
250+
nrf_errata_30_workaround();
251+
}
252+
#endif
178253
struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type);
179254
clock_control_cb_t callback = sub_data->cb;
180255
void *user_data = sub_data->user_data;

0 commit comments

Comments
 (0)