Skip to content

Commit aa34fa8

Browse files
mstasiaknordickartben
authored andcommitted
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. Signed-off-by: Michał Stasiak <michal.stasiak@nordicsemi.no>
1 parent c3139c5 commit aa34fa8

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-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: 82 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

@@ -172,9 +173,90 @@ static void set_on_state(uint32_t *flags)
172173
irq_unlock(key);
173174
}
174175

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

0 commit comments

Comments
 (0)