From ab470a90524e9dc2f2a84d79707962b582109c4d Mon Sep 17 00:00:00 2001 From: Piotr Pryga Date: Fri, 6 Dec 2024 14:20:28 +0100 Subject: [PATCH] mpsl: clock_ctrl: Fix nRF52 LFCLK accuracy when LFSYNTH selected The nrf clock control driver doesn't enable HFXO when LFSYNTH is selected as a source of LFCLK. That causes the accuracy of LFCLK to be not within the expected by BT Core Specification range up to 500 ppm. To fix the problem the mpsl clock control integration layer has to request the hfxo in case the lfclk is requested with LFSYNTH as a source. Use of z_nrf_clock_bt_ctlr_hf_release makes the call to be faster. That unfortunately requires reference counting do avoid release of HFXO later in runtime by MPSL. For that reason the m_hfclk_request and m_hfclk_release are used. Signed-off-by: Piotr Pryga --- subsys/mpsl/clock_ctrl/mpsl_clock_ctrl.c | 104 +++++++++++++---------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/subsys/mpsl/clock_ctrl/mpsl_clock_ctrl.c b/subsys/mpsl/clock_ctrl/mpsl_clock_ctrl.c index f0eaf4b6d992..3a7d7b078d94 100644 --- a/subsys/mpsl/clock_ctrl/mpsl_clock_ctrl.c +++ b/subsys/mpsl/clock_ctrl/mpsl_clock_ctrl.c @@ -105,6 +105,52 @@ static int32_t m_lfclk_wait(void) #if defined(CONFIG_CLOCK_CONTROL_NRF) +static void m_hfclk_request(void) +{ + /* The z_nrf_clock_bt_ctlr_hf_request doesn't count references to HFCLK, + * it is caller responsibility handle requests and releases counting. + */ + if (atomic_inc(&m_hfclk_refcnt) > (atomic_val_t)0) { + return; + } + + z_nrf_clock_bt_ctlr_hf_request(); +} + +static void m_hfclk_release(void) +{ + /* The z_nrf_clock_bt_ctlr_hf_request doesn't count references to HFCLK, + * it is caller responsibility to not release the clock if there is + * other request pending. + */ + if (atomic_get(&m_hfclk_refcnt) < (atomic_val_t)1) { + return; + } + + if (atomic_dec(&m_hfclk_refcnt) > (atomic_val_t)1) { + return; + } + + z_nrf_clock_bt_ctlr_hf_release(); +} + +static bool m_hfclk_is_running(void) +{ + if (atomic_get(&m_hfclk_refcnt) > (atomic_val_t)0) { + nrf_clock_hfclk_t type; + + unsigned int key = irq_lock(); + + (void)nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &type); + + irq_unlock(key); + + return ((type == NRF_CLOCK_HFCLK_HIGH_ACCURACY) ? true : false); + } + + return false; +} + static void m_lfclk_calibration_start(void) { if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) { @@ -126,6 +172,13 @@ static int32_t m_lfclk_request(void) struct onoff_manager *mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF); int32_t err; + /* Workaround for NRFX-6865. The nrf clock control as well as nrfx_clock doesn't enable + * HFXO when LFSYNTH is selected as LFCLK source. Remove the code when nrfx is fixed. + */ + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH)) { + m_hfclk_request(); + } + sys_notify_init_callback(&m_lfclk_state.cli.notify, lfclk_request_cb); (void)k_sem_init(&m_lfclk_state.sem, 0, 1); @@ -150,55 +203,16 @@ static int32_t m_lfclk_release(void) return err; } - atomic_dec(&m_lfclk_state.m_clk_refcnt); - - return 0; -} - -static void m_hfclk_request(void) -{ - /* The z_nrf_clock_bt_ctlr_hf_request doesn't count references to HFCLK, - * it is caller responsibility handle requests and releases counting. - */ - if (atomic_inc(&m_hfclk_refcnt) > (atomic_val_t)0) { - return; - } - - z_nrf_clock_bt_ctlr_hf_request(); -} - -static void m_hfclk_release(void) -{ - /* The z_nrf_clock_bt_ctlr_hf_request doesn't count references to HFCLK, - * it is caller responsibility to not release the clock if there is - * other request pending. + /* Workaround for NRFX-6865. The nrf clock control as well as nrfx_clock doesn't enable + * HFXO when LFSYNTH is selected as LFCLK source. Remove the code when nrfx is fixed. */ - if (atomic_get(&m_hfclk_refcnt) < (atomic_val_t)1) { - return; - } - - if (atomic_dec(&m_hfclk_refcnt) > (atomic_val_t)1) { - return; + if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH)) { + m_hfclk_release(); } - z_nrf_clock_bt_ctlr_hf_release(); -} - -static bool m_hfclk_is_running(void) -{ - if (atomic_get(&m_hfclk_refcnt) > (atomic_val_t)0) { - nrf_clock_hfclk_t type; - - unsigned int key = irq_lock(); - - (void)nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &type); - - irq_unlock(key); - - return ((type == NRF_CLOCK_HFCLK_HIGH_ACCURACY) ? true : false); - } + atomic_dec(&m_lfclk_state.m_clk_refcnt); - return false; + return 0; } #elif defined(CONFIG_CLOCK_CONTROL_NRF2)