|
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 |
|
@@ -84,6 +85,11 @@ static uint64_t hf_stop_tstamp; |
84 | 85 | static struct onoff_client lfsynth_cli; |
85 | 86 | #endif |
86 | 87 |
|
| 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 | + |
87 | 93 | static struct nrf_clock_control_sub_data *get_sub_data(const struct device *dev, |
88 | 94 | enum clock_control_nrf_type type) |
89 | 95 | { |
@@ -172,9 +178,78 @@ static void set_on_state(uint32_t *flags) |
172 | 178 | irq_unlock(key); |
173 | 179 | } |
174 | 180 |
|
| 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 | + |
175 | 245 | static void clkstarted_handle(const struct device *dev, |
176 | 246 | enum clock_control_nrf_type type) |
177 | 247 | { |
| 248 | +#if CONFIG_CLOCK_CONTROL_NRF_HF_CALIBRATION |
| 249 | + if (type == CLOCK_CONTROL_NRF_TYPE_HFCLK) { |
| 250 | + nrf_errata_30_workaround(); |
| 251 | + } |
| 252 | +#endif |
178 | 253 | struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type); |
179 | 254 | clock_control_cb_t callback = sub_data->cb; |
180 | 255 | void *user_data = sub_data->user_data; |
|
0 commit comments