|
14 | 14 | #include <zephyr/logging/log.h>
|
15 | 15 | #include <zephyr/shell/shell.h>
|
16 | 16 | #include <zephyr/irq.h>
|
| 17 | +#include <nrf_erratas.h> |
17 | 18 |
|
18 | 19 | LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
|
19 | 20 |
|
@@ -172,9 +173,90 @@ static void set_on_state(uint32_t *flags)
|
172 | 173 | irq_unlock(key);
|
173 | 174 | }
|
174 | 175 |
|
| 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 | + |
175 | 252 | static void clkstarted_handle(const struct device *dev,
|
176 | 253 | enum clock_control_nrf_type type)
|
177 | 254 | {
|
| 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 |
178 | 260 | struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type);
|
179 | 261 | clock_control_cb_t callback = sub_data->cb;
|
180 | 262 | void *user_data = sub_data->user_data;
|
|
0 commit comments