LCOV - code coverage report
Current view: top level - drivers/clock_control - clock_control_nrf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 108 253 42.7 %
Date: 2022-08-18 11:36:24 Functions: 16 38 42.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 27 91 29.7 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016-2020 Nordic Semiconductor ASA
       3                 :            :  * Copyright (c) 2016 Vinayak Kariappa Chettimada
       4                 :            :  *
       5                 :            :  * SPDX-License-Identifier: Apache-2.0
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <soc.h>
       9                 :            : #include <sys/onoff.h>
      10                 :            : #include <drivers/clock_control.h>
      11                 :            : #include <drivers/clock_control/nrf_clock_control.h>
      12                 :            : #include "nrf_clock_calibration.h"
      13                 :            : #include <nrfx_clock.h>
      14                 :            : #include <logging/log.h>
      15                 :            : #include <shell/shell.h>
      16                 :            : 
      17                 :            : LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
      18                 :            : 
      19                 :            : #define DT_DRV_COMPAT nordic_nrf_clock
      20                 :            : 
      21                 :            : 
      22                 :            : #define CTX_ONOFF               BIT(6)
      23                 :            : #define CTX_API                 BIT(7)
      24                 :            : #define CTX_MASK (CTX_ONOFF | CTX_API)
      25                 :            : 
      26                 :            : #define STATUS_MASK             0x7
      27                 :            : #define GET_STATUS(flags)       (flags & STATUS_MASK)
      28                 :            : #define GET_CTX(flags)          (flags & CTX_MASK)
      29                 :            : 
      30                 :            : /* Used only by HF clock */
      31                 :            : #define HF_USER_BT              BIT(0)
      32                 :            : #define HF_USER_GENERIC         BIT(1)
      33                 :            : 
      34                 :            : /* Helper logging macros which prepends subsys name to the log. */
      35                 :            : #ifdef CONFIG_LOG
      36                 :            : #define CLOCK_LOG(lvl, dev, subsys, ...) \
      37                 :            :         LOG_##lvl("%s: " GET_ARG_N(1, __VA_ARGS__), \
      38                 :            :                 get_sub_config(dev, (enum clock_control_nrf_type)subsys)->name \
      39                 :            :                 COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__),\
      40                 :            :                                 (), (, GET_ARGS_LESS_N(1, __VA_ARGS__))))
      41                 :            : #else
      42                 :            : #define CLOCK_LOG(...)
      43                 :            : #endif
      44                 :            : 
      45                 :            : #define ERR(dev, subsys, ...) CLOCK_LOG(ERR, dev, subsys, __VA_ARGS__)
      46                 :            : #define WRN(dev, subsys, ...) CLOCK_LOG(WRN, dev, subsys, __VA_ARGS__)
      47                 :            : #define INF(dev, subsys, ...) CLOCK_LOG(INF, dev, subsys, __VA_ARGS__)
      48                 :            : #define DBG(dev, subsys, ...) CLOCK_LOG(DBG, dev, subsys, __VA_ARGS__)
      49                 :            : 
      50                 :            : /* Clock subsys structure */
      51                 :            : struct nrf_clock_control_sub_data {
      52                 :            :         clock_control_cb_t cb;
      53                 :            :         void *user_data;
      54                 :            :         uint32_t flags;
      55                 :            : };
      56                 :            : 
      57                 :            : typedef void (*clk_ctrl_func_t)(void);
      58                 :            : 
      59                 :            : /* Clock subsys static configuration */
      60                 :            : struct nrf_clock_control_sub_config {
      61                 :            :         clk_ctrl_func_t start;          /* Clock start function */
      62                 :            :         clk_ctrl_func_t stop;           /* Clock stop function */
      63                 :            : #ifdef CONFIG_LOG
      64                 :            :         const char *name;
      65                 :            : #endif
      66                 :            : };
      67                 :            : 
      68                 :            : struct nrf_clock_control_data {
      69                 :            :         struct onoff_manager mgr[CLOCK_CONTROL_NRF_TYPE_COUNT];
      70                 :            :         struct nrf_clock_control_sub_data subsys[CLOCK_CONTROL_NRF_TYPE_COUNT];
      71                 :            : };
      72                 :            : 
      73                 :            : struct nrf_clock_control_config {
      74                 :            :         struct nrf_clock_control_sub_config
      75                 :            :                                         subsys[CLOCK_CONTROL_NRF_TYPE_COUNT];
      76                 :            : };
      77                 :            : 
      78                 :            : static atomic_t hfclk_users;
      79                 :            : static uint64_t hf_start_tstamp;
      80                 :            : static uint64_t hf_stop_tstamp;
      81                 :            : 
      82                 :          6 : static struct nrf_clock_control_sub_data *get_sub_data(const struct device *dev,
      83                 :            :                                                        enum clock_control_nrf_type type)
      84                 :            : {
      85                 :          6 :         struct nrf_clock_control_data *data = dev->data;
      86                 :            : 
      87                 :          6 :         return &data->subsys[type];
      88                 :            : }
      89                 :            : 
      90                 :          1 : static const struct nrf_clock_control_sub_config *get_sub_config(const struct device *dev,
      91                 :            :                                                                  enum clock_control_nrf_type type)
      92                 :            : {
      93                 :          1 :         const struct nrf_clock_control_config *config =
      94                 :            :                                                 dev->config;
      95                 :            : 
      96                 :          1 :         return &config->subsys[type];
      97                 :            : }
      98                 :            : 
      99                 :          6 : static struct onoff_manager *get_onoff_manager(const struct device *dev,
     100                 :            :                                                enum clock_control_nrf_type type)
     101                 :            : {
     102                 :          6 :         struct nrf_clock_control_data *data = dev->data;
     103                 :            : 
     104                 :          6 :         return &data->mgr[type];
     105                 :            : }
     106                 :            : 
     107                 :            : 
     108                 :            : #define CLOCK_DEVICE DEVICE_DT_GET(DT_NODELABEL(clock))
     109                 :            : 
     110                 :          0 : struct onoff_manager *z_nrf_clock_control_get_onoff(clock_control_subsys_t sys)
     111                 :            : {
     112                 :          0 :         return get_onoff_manager(CLOCK_DEVICE,
     113                 :            :                                 (enum clock_control_nrf_type)sys);
     114                 :            : }
     115                 :            : 
     116                 :          0 : static enum clock_control_status get_status(const struct device *dev,
     117                 :            :                                             clock_control_subsys_t subsys)
     118                 :            : {
     119                 :          0 :         enum clock_control_nrf_type type = (enum clock_control_nrf_type)subsys;
     120                 :            : 
     121         [ #  # ]:          0 :         __ASSERT_NO_MSG(type < CLOCK_CONTROL_NRF_TYPE_COUNT);
     122                 :            : 
     123                 :          0 :         return GET_STATUS(get_sub_data(dev, type)->flags);
     124                 :            : }
     125                 :            : 
     126                 :          0 : static int set_off_state(uint32_t *flags, uint32_t ctx)
     127                 :            : {
     128                 :          0 :         int err = 0;
     129                 :          0 :         int key = irq_lock();
     130                 :          0 :         uint32_t current_ctx = GET_CTX(*flags);
     131                 :            : 
     132   [ #  #  #  # ]:          0 :         if ((current_ctx != 0) && (current_ctx != ctx)) {
     133                 :          0 :                 err = -EPERM;
     134                 :            :         } else {
     135                 :          0 :                 *flags = CLOCK_CONTROL_STATUS_OFF;
     136                 :            :         }
     137                 :            : 
     138                 :          0 :         irq_unlock(key);
     139                 :            : 
     140                 :          0 :         return err;
     141                 :            : }
     142                 :            : 
     143                 :          1 : static int set_starting_state(uint32_t *flags, uint32_t ctx)
     144                 :            : {
     145                 :          1 :         int err = 0;
     146                 :          1 :         int key = irq_lock();
     147                 :          1 :         uint32_t current_ctx = GET_CTX(*flags);
     148                 :            : 
     149         [ +  - ]:          1 :         if ((*flags & (STATUS_MASK)) == CLOCK_CONTROL_STATUS_OFF) {
     150                 :          1 :                 *flags = CLOCK_CONTROL_STATUS_STARTING | ctx;
     151         [ #  # ]:          0 :         } else if (current_ctx != ctx) {
     152                 :          0 :                 err = -EPERM;
     153                 :            :         } else {
     154                 :          0 :                 err = -EALREADY;
     155                 :            :         }
     156                 :            : 
     157                 :          1 :         irq_unlock(key);
     158                 :            : 
     159                 :          1 :         return err;
     160                 :            : }
     161                 :            : 
     162                 :          1 : static void set_on_state(uint32_t *flags)
     163                 :            : {
     164                 :          1 :         int key = irq_lock();
     165                 :            : 
     166                 :          1 :         *flags = CLOCK_CONTROL_STATUS_ON | GET_CTX(*flags);
     167                 :          1 :         irq_unlock(key);
     168                 :          1 : }
     169                 :            : 
     170                 :          1 : static void clkstarted_handle(const struct device *dev,
     171                 :            :                               enum clock_control_nrf_type type)
     172                 :            : {
     173                 :          1 :         struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type);
     174                 :          1 :         clock_control_cb_t callback = sub_data->cb;
     175                 :          1 :         void *user_data = sub_data->user_data;
     176                 :            : 
     177                 :          1 :         sub_data->cb = NULL;
     178                 :          1 :         set_on_state(&sub_data->flags);
     179         [ +  - ]:          1 :         DBG(dev, type, "Clock started");
     180                 :            : 
     181         [ +  - ]:          1 :         if (callback) {
     182                 :          1 :                 callback(dev, (clock_control_subsys_t)type, user_data);
     183                 :            :         }
     184                 :          1 : }
     185                 :            : 
     186                 :            : static inline void anomaly_132_workaround(void)
     187                 :            : {
     188                 :            : #if (CONFIG_NRF52_ANOMALY_132_DELAY_US - 0)
     189                 :            :         static bool once;
     190                 :            : 
     191                 :            :         if (!once) {
     192                 :            :                 k_busy_wait(CONFIG_NRF52_ANOMALY_132_DELAY_US);
     193                 :            :                 once = true;
     194                 :            :         }
     195                 :            : #endif
     196                 :            : }
     197                 :            : 
     198                 :          1 : static void lfclk_start(void)
     199                 :            : {
     200                 :            :         if (IS_ENABLED(CONFIG_NRF52_ANOMALY_132_WORKAROUND)) {
     201                 :            :                 anomaly_132_workaround();
     202                 :            :         }
     203                 :            : 
     204                 :          1 :         nrfx_clock_lfclk_start();
     205                 :          1 : }
     206                 :            : 
     207                 :          0 : static void lfclk_stop(void)
     208                 :            : {
     209                 :            :         if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) {
     210                 :            :                 z_nrf_clock_calibration_lfclk_stopped();
     211                 :            :         }
     212                 :            : 
     213                 :          0 :         nrfx_clock_lfclk_stop();
     214                 :          0 : }
     215                 :            : 
     216                 :          0 : static void hfclk_start(void)
     217                 :            : {
     218                 :            :         if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) {
     219                 :            :                 hf_start_tstamp = k_uptime_get();
     220                 :            :         }
     221                 :            : 
     222                 :          0 :         nrfx_clock_hfclk_start();
     223                 :          0 : }
     224                 :            : 
     225                 :          0 : static void hfclk_stop(void)
     226                 :            : {
     227                 :            :         if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) {
     228                 :            :                 hf_stop_tstamp = k_uptime_get();
     229                 :            :         }
     230                 :            : 
     231                 :          0 :         nrfx_clock_hfclk_stop();
     232                 :          0 : }
     233                 :            : 
     234                 :            : #if NRF_CLOCK_HAS_HFCLK192M
     235                 :          0 : static void hfclk192m_start(void)
     236                 :            : {
     237                 :          0 :         nrfx_clock_start(NRF_CLOCK_DOMAIN_HFCLK192M);
     238                 :          0 : }
     239                 :            : 
     240                 :          0 : static void hfclk192m_stop(void)
     241                 :            : {
     242                 :          0 :         nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK192M);
     243                 :          0 : }
     244                 :            : #endif
     245                 :            : 
     246                 :            : #if NRF_CLOCK_HAS_HFCLKAUDIO
     247                 :          0 : static void hfclkaudio_start(void)
     248                 :            : {
     249                 :          0 :         nrfx_clock_start(NRF_CLOCK_DOMAIN_HFCLKAUDIO);
     250                 :          0 : }
     251                 :            : 
     252                 :          0 : static void hfclkaudio_stop(void)
     253                 :            : {
     254                 :          0 :         nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLKAUDIO);
     255                 :          0 : }
     256                 :            : #endif
     257                 :            : 
     258                 :          0 : static uint32_t *get_hf_flags(void)
     259                 :            : {
     260                 :          0 :         struct nrf_clock_control_data *data = CLOCK_DEVICE->data;
     261                 :            : 
     262                 :          0 :         return &data->subsys[CLOCK_CONTROL_NRF_TYPE_HFCLK].flags;
     263                 :            : }
     264                 :            : 
     265                 :          0 : static void generic_hfclk_start(void)
     266                 :            : {
     267                 :            :         nrf_clock_hfclk_t type;
     268                 :          0 :         bool already_started = false;
     269                 :          0 :         int key = irq_lock();
     270                 :            : 
     271                 :          0 :         hfclk_users |= HF_USER_GENERIC;
     272         [ #  # ]:          0 :         if (hfclk_users & HF_USER_BT) {
     273                 :          0 :                 (void)nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &type);
     274         [ #  # ]:          0 :                 if (type == NRF_CLOCK_HFCLK_HIGH_ACCURACY) {
     275                 :          0 :                         already_started = true;
     276                 :            :                         /* Set on state in case clock interrupt comes and we
     277                 :            :                          * want to avoid handling that.
     278                 :            :                          */
     279                 :          0 :                         set_on_state(get_hf_flags());
     280                 :            :                 }
     281                 :            :         }
     282                 :            : 
     283                 :          0 :         irq_unlock(key);
     284                 :            : 
     285         [ #  # ]:          0 :         if (already_started) {
     286                 :            :                 /* Clock already started by z_nrf_clock_bt_ctlr_hf_request */
     287                 :          0 :                 clkstarted_handle(CLOCK_DEVICE,
     288                 :            :                                   CLOCK_CONTROL_NRF_TYPE_HFCLK);
     289                 :          0 :                 return;
     290                 :            :         }
     291                 :            : 
     292                 :          0 :         hfclk_start();
     293                 :            : }
     294                 :            : 
     295                 :          0 : static void generic_hfclk_stop(void)
     296                 :            : {
     297         [ #  # ]:          0 :         if (atomic_and(&hfclk_users, ~HF_USER_GENERIC) & HF_USER_BT) {
     298                 :            :                 /* bt still requesting the clock. */
     299                 :          0 :                 return;
     300                 :            :         }
     301                 :            : 
     302                 :          0 :         hfclk_stop();
     303                 :            : }
     304                 :            : 
     305                 :            : 
     306                 :          0 : void z_nrf_clock_bt_ctlr_hf_request(void)
     307                 :            : {
     308         [ #  # ]:          0 :         if (atomic_or(&hfclk_users, HF_USER_BT) & HF_USER_GENERIC) {
     309                 :            :                 /* generic request already activated clock. */
     310                 :          0 :                 return;
     311                 :            :         }
     312                 :            : 
     313                 :          0 :         hfclk_start();
     314                 :            : }
     315                 :            : 
     316                 :          0 : void z_nrf_clock_bt_ctlr_hf_release(void)
     317                 :            : {
     318         [ #  # ]:          0 :         if (atomic_and(&hfclk_users, ~HF_USER_BT) & HF_USER_GENERIC) {
     319                 :            :                 /* generic still requesting the clock. */
     320                 :          0 :                 return;
     321                 :            :         }
     322                 :            : 
     323                 :          0 :         hfclk_stop();
     324                 :            : }
     325                 :            : 
     326                 :          0 : static int stop(const struct device *dev, clock_control_subsys_t subsys,
     327                 :            :                 uint32_t ctx)
     328                 :            : {
     329                 :          0 :         enum clock_control_nrf_type type = (enum clock_control_nrf_type)subsys;
     330                 :          0 :         struct nrf_clock_control_sub_data *subdata = get_sub_data(dev, type);
     331                 :            :         int err;
     332                 :            : 
     333         [ #  # ]:          0 :         __ASSERT_NO_MSG(type < CLOCK_CONTROL_NRF_TYPE_COUNT);
     334                 :            : 
     335                 :          0 :         err = set_off_state(&subdata->flags, ctx);
     336         [ #  # ]:          0 :         if (err < 0) {
     337                 :          0 :                 return err;
     338                 :            :         }
     339                 :            : 
     340                 :          0 :         get_sub_config(dev, type)->stop();
     341                 :            : 
     342                 :          0 :         return 0;
     343                 :            : }
     344                 :            : 
     345                 :          0 : static int api_stop(const struct device *dev, clock_control_subsys_t subsys)
     346                 :            : {
     347                 :          0 :         return stop(dev, subsys, CTX_API);
     348                 :            : }
     349                 :            : 
     350                 :          1 : static int async_start(const struct device *dev, clock_control_subsys_t subsys,
     351                 :            :                         clock_control_cb_t cb, void *user_data, uint32_t ctx)
     352                 :            : {
     353                 :          1 :         enum clock_control_nrf_type type = (enum clock_control_nrf_type)subsys;
     354                 :          1 :         struct nrf_clock_control_sub_data *subdata = get_sub_data(dev, type);
     355                 :            :         int err;
     356                 :            : 
     357                 :          1 :         err = set_starting_state(&subdata->flags, ctx);
     358         [ -  + ]:          1 :         if (err < 0) {
     359                 :          0 :                 return err;
     360                 :            :         }
     361                 :            : 
     362                 :          1 :         subdata->cb = cb;
     363                 :          1 :         subdata->user_data = user_data;
     364                 :            : 
     365                 :          1 :          get_sub_config(dev, type)->start();
     366                 :            : 
     367                 :          1 :         return 0;
     368                 :            : }
     369                 :            : 
     370                 :          0 : static int api_start(const struct device *dev, clock_control_subsys_t subsys,
     371                 :            :                      clock_control_cb_t cb, void *user_data)
     372                 :            : {
     373                 :          0 :         return async_start(dev, subsys, cb, user_data, CTX_API);
     374                 :            : }
     375                 :            : 
     376                 :          0 : static void blocking_start_callback(const struct device *dev,
     377                 :            :                                     clock_control_subsys_t subsys,
     378                 :            :                                     void *user_data)
     379                 :            : {
     380                 :          0 :         struct k_sem *sem = user_data;
     381                 :            : 
     382                 :          0 :         k_sem_give(sem);
     383                 :          0 : }
     384                 :            : 
     385                 :          0 : static int api_blocking_start(const struct device *dev,
     386                 :            :                               clock_control_subsys_t subsys)
     387                 :            : {
     388                 :          0 :         struct k_sem sem = Z_SEM_INITIALIZER(sem, 0, 1);
     389                 :            :         int err;
     390                 :            : 
     391                 :            :         if (!IS_ENABLED(CONFIG_MULTITHREADING)) {
     392                 :            :                 return -ENOTSUP;
     393                 :            :         }
     394                 :            : 
     395                 :          0 :         err = api_start(dev, subsys, blocking_start_callback, &sem);
     396         [ #  # ]:          0 :         if (err < 0) {
     397                 :          0 :                 return err;
     398                 :            :         }
     399                 :            : 
     400                 :          0 :         return k_sem_take(&sem, K_MSEC(500));
     401                 :            : }
     402                 :            : 
     403                 :          1 : static clock_control_subsys_t get_subsys(struct onoff_manager *mgr)
     404                 :            : {
     405                 :          1 :         struct nrf_clock_control_data *data = CLOCK_DEVICE->data;
     406                 :          1 :         size_t offset = (size_t)(mgr - data->mgr);
     407                 :            : 
     408                 :          1 :         return (clock_control_subsys_t)offset;
     409                 :            : }
     410                 :            : 
     411                 :          0 : static void onoff_stop(struct onoff_manager *mgr,
     412                 :            :                         onoff_notify_fn notify)
     413                 :            : {
     414                 :            :         int res;
     415                 :            : 
     416                 :          0 :         res = stop(CLOCK_DEVICE, get_subsys(mgr), CTX_ONOFF);
     417                 :          0 :         notify(mgr, res);
     418                 :          0 : }
     419                 :            : 
     420                 :          1 : static void onoff_started_callback(const struct device *dev,
     421                 :            :                                    clock_control_subsys_t sys,
     422                 :            :                                    void *user_data)
     423                 :            : {
     424                 :          1 :         enum clock_control_nrf_type type = (enum clock_control_nrf_type)sys;
     425                 :          1 :         struct onoff_manager *mgr = get_onoff_manager(dev, type);
     426                 :          1 :         onoff_notify_fn notify = user_data;
     427                 :            : 
     428                 :          1 :         notify(mgr, 0);
     429                 :          1 : }
     430                 :            : 
     431                 :          1 : static void onoff_start(struct onoff_manager *mgr,
     432                 :            :                         onoff_notify_fn notify)
     433                 :            : {
     434                 :            :         int err;
     435                 :            : 
     436                 :          1 :         err = async_start(CLOCK_DEVICE, get_subsys(mgr),
     437                 :            :                           onoff_started_callback, notify, CTX_ONOFF);
     438         [ -  + ]:          1 :         if (err < 0) {
     439                 :          0 :                 notify(mgr, err);
     440                 :            :         }
     441                 :          1 : }
     442                 :            : 
     443                 :            : /** @brief Wait for LF clock availability or stability.
     444                 :            :  *
     445                 :            :  * If LF clock source is SYNTH or RC then there is no distinction between
     446                 :            :  * availability and stability. In case of XTAL source clock, system is initially
     447                 :            :  * starting RC and then seamlessly switches to XTAL. Running RC means clock
     448                 :            :  * availability and running target source means stability, That is because
     449                 :            :  * significant difference in startup time (<1ms vs >200ms).
     450                 :            :  *
     451                 :            :  * In order to get event/interrupt when RC is ready (allowing CPU sleeping) two
     452                 :            :  * stage startup sequence is used. Initially, LF source is set to RC and when
     453                 :            :  * LFSTARTED event is handled it is reconfigured to the target source clock.
     454                 :            :  * This approach is implemented in nrfx_clock driver and utilized here.
     455                 :            :  *
     456                 :            :  * @param mode Start mode.
     457                 :            :  */
     458                 :          1 : static void lfclk_spinwait(enum nrf_lfclk_start_mode mode)
     459                 :            : {
     460                 :            :         static const nrf_clock_domain_t d = NRF_CLOCK_DOMAIN_LFCLK;
     461                 :            :         static const nrf_clock_lfclk_t target_type =
     462                 :            :                 /* For sources XTAL, EXT_LOW_SWING, and EXT_FULL_SWING,
     463                 :            :                  * NRF_CLOCK_LFCLK_Xtal is returned as the type of running clock.
     464                 :            :                  */
     465                 :            :                 (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL) ||
     466                 :            :                  IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING) ||
     467                 :            :                  IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING))
     468                 :            :                 ? NRF_CLOCK_LFCLK_Xtal
     469                 :            :                 : CLOCK_CONTROL_NRF_K32SRC;
     470                 :            :         nrf_clock_lfclk_t type;
     471                 :            : 
     472         [ -  + ]:          1 :         if ((mode == CLOCK_CONTROL_NRF_LF_START_AVAILABLE) &&
     473   [ #  #  #  # ]:          0 :             (target_type == NRF_CLOCK_LFCLK_Xtal) &&
     474                 :          0 :             (nrf_clock_lf_srccopy_get(NRF_CLOCK) == CLOCK_CONTROL_NRF_K32SRC)) {
     475                 :            :                 /* If target clock source is using XTAL then due to two-stage
     476                 :            :                  * clock startup sequence, RC might already be running.
     477                 :            :                  * It can be determined by checking current LFCLK source. If it
     478                 :            :                  * is set to the target clock source then it means that RC was
     479                 :            :                  * started.
     480                 :            :                  */
     481                 :          0 :                 return;
     482                 :            :         }
     483                 :            : 
     484   [ +  -  +  - ]:          1 :         bool isr_mode = k_is_in_isr() || k_is_pre_kernel();
     485         [ +  - ]:          1 :         int key = isr_mode ? irq_lock() : 0;
     486                 :            : 
     487         [ -  + ]:          1 :         if (!isr_mode) {
     488                 :          0 :                 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
     489                 :            :         }
     490                 :            : 
     491         [ +  + ]:          3 :         while (!(nrfx_clock_is_running(d, (void *)&type)
     492         [ -  + ]:          1 :                  && ((type == target_type)
     493         [ #  # ]:          0 :                      || (mode == CLOCK_CONTROL_NRF_LF_START_AVAILABLE)))) {
     494                 :            :                 /* Synth source start is almost instant and LFCLKSTARTED may
     495                 :            :                  * happen before calling idle. That would lead to deadlock.
     496                 :            :                  */
     497                 :            :                 if (!IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH)) {
     498         [ +  - ]:          2 :                         if (isr_mode || !IS_ENABLED(CONFIG_MULTITHREADING)) {
     499                 :          2 :                                 k_cpu_atomic_idle(key);
     500                 :            :                         } else {
     501                 :          0 :                                 k_msleep(1);
     502                 :            :                         }
     503                 :            :                 }
     504                 :            : 
     505                 :            :                 /* Clock interrupt is locked, LFCLKSTARTED is handled here. */
     506         [ +  - ]:          2 :                 if ((target_type ==  NRF_CLOCK_LFCLK_Xtal)
     507         [ +  + ]:          2 :                     && (nrf_clock_lf_src_get(NRF_CLOCK) == NRF_CLOCK_LFCLK_RC)
     508         [ +  - ]:          1 :                     && nrf_clock_event_check(NRF_CLOCK,
     509                 :            :                                              NRF_CLOCK_EVENT_LFCLKSTARTED)) {
     510                 :          1 :                         nrf_clock_event_clear(NRF_CLOCK,
     511                 :            :                                               NRF_CLOCK_EVENT_LFCLKSTARTED);
     512                 :          1 :                         nrf_clock_lf_src_set(NRF_CLOCK,
     513                 :            :                                              CLOCK_CONTROL_NRF_K32SRC);
     514                 :            : 
     515                 :            :                         /* Clear pending interrupt, otherwise new clock event
     516                 :            :                          * would not wake up from idle.
     517                 :            :                          */
     518                 :          1 :                         NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
     519                 :          1 :                         nrf_clock_task_trigger(NRF_CLOCK,
     520                 :            :                                                NRF_CLOCK_TASK_LFCLKSTART);
     521                 :            :                 }
     522                 :            :         }
     523                 :            : 
     524         [ +  - ]:          1 :         if (isr_mode) {
     525                 :          1 :                 irq_unlock(key);
     526                 :            :         } else {
     527                 :          0 :                 nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
     528                 :            :         }
     529                 :            : }
     530                 :            : 
     531                 :          1 : void z_nrf_clock_control_lf_on(enum nrf_lfclk_start_mode start_mode)
     532                 :            : {
     533                 :            :         static atomic_t on;
     534                 :            :         static struct onoff_client cli;
     535                 :            : 
     536         [ +  - ]:          1 :         if (atomic_set(&on, 1) == 0) {
     537                 :            :                 int err;
     538                 :            :                 struct onoff_manager *mgr =
     539                 :          1 :                                 get_onoff_manager(CLOCK_DEVICE,
     540                 :            :                                                   CLOCK_CONTROL_NRF_TYPE_LFCLK);
     541                 :            : 
     542                 :          1 :                 sys_notify_init_spinwait(&cli.notify);
     543                 :          1 :                 err = onoff_request(mgr, &cli);
     544         [ -  + ]:          1 :                 __ASSERT_NO_MSG(err >= 0);
     545                 :            :         }
     546                 :            : 
     547                 :            :         /* In case of simulated board leave immediately. */
     548                 :            :         if (IS_ENABLED(CONFIG_SOC_SERIES_BSIM_NRFXX)) {
     549                 :            :                 return;
     550                 :            :         }
     551                 :            : 
     552      [ +  -  - ]:          1 :         switch (start_mode) {
     553                 :          1 :         case CLOCK_CONTROL_NRF_LF_START_AVAILABLE:
     554                 :            :         case CLOCK_CONTROL_NRF_LF_START_STABLE:
     555                 :          1 :                 lfclk_spinwait(start_mode);
     556                 :          1 :                 break;
     557                 :            : 
     558                 :          0 :         case CLOCK_CONTROL_NRF_LF_START_NOWAIT:
     559                 :          0 :                 break;
     560                 :            : 
     561                 :          0 :         default:
     562                 :          0 :                 __ASSERT_NO_MSG(false);
     563                 :            :         }
     564                 :            : }
     565                 :            : 
     566                 :          1 : static void clock_event_handler(nrfx_clock_evt_type_t event)
     567                 :            : {
     568                 :          1 :         const struct device *dev = CLOCK_DEVICE;
     569                 :            : 
     570   [ -  -  -  +  :          1 :         switch (event) {
                   -  - ]
     571                 :          0 :         case NRFX_CLOCK_EVT_HFCLK_STARTED:
     572                 :            :         {
     573                 :            :                 struct nrf_clock_control_sub_data *data =
     574                 :          0 :                                 get_sub_data(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK);
     575                 :            : 
     576                 :            :                 /* Check needed due to anomaly 201:
     577                 :            :                  * HFCLKSTARTED may be generated twice.
     578                 :            :                  */
     579         [ #  # ]:          0 :                 if (GET_STATUS(data->flags) == CLOCK_CONTROL_STATUS_STARTING) {
     580                 :          0 :                         clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK);
     581                 :            :                 }
     582                 :            : 
     583                 :          0 :                 break;
     584                 :            :         }
     585                 :            : #if NRF_CLOCK_HAS_HFCLK192M
     586                 :          0 :         case NRFX_CLOCK_EVT_HFCLK192M_STARTED:
     587                 :          0 :                 clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLK192M);
     588                 :          0 :                 break;
     589                 :            : #endif
     590                 :            : #if NRF_CLOCK_HAS_HFCLKAUDIO
     591                 :          0 :         case NRFX_CLOCK_EVT_HFCLKAUDIO_STARTED:
     592                 :          0 :                 clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_HFCLKAUDIO);
     593                 :          0 :                 break;
     594                 :            : #endif
     595                 :          1 :         case NRFX_CLOCK_EVT_LFCLK_STARTED:
     596                 :            :                 if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) {
     597                 :            :                         z_nrf_clock_calibration_lfclk_started();
     598                 :            :                 }
     599                 :          1 :                 clkstarted_handle(dev, CLOCK_CONTROL_NRF_TYPE_LFCLK);
     600                 :          1 :                 break;
     601                 :          0 :         case NRFX_CLOCK_EVT_CAL_DONE:
     602                 :            :                 if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) {
     603                 :            :                         z_nrf_clock_calibration_done_handler();
     604                 :            :                 } else {
     605                 :            :                         /* Should not happen when calibration is disabled. */
     606                 :          0 :                         __ASSERT_NO_MSG(false);
     607                 :            :                 }
     608                 :          0 :                 break;
     609                 :          0 :         default:
     610                 :          0 :                 __ASSERT_NO_MSG(0);
     611                 :          0 :                 break;
     612                 :            :         }
     613                 :          1 : }
     614                 :            : 
     615                 :          1 : static void hfclkaudio_init(void)
     616                 :            : {
     617                 :            : #if DT_NODE_HAS_PROP(DT_NODELABEL(clock), hfclkaudio_frequency)
     618                 :            :         const uint32_t frequency =
     619                 :            :                 DT_PROP(DT_NODELABEL(clock), hfclkaudio_frequency);
     620                 :            :         /* As specified in the nRF5340 PS:
     621                 :            :          *
     622                 :            :          * FREQ_VALUE = 2^16 * ((12 * f_out / 32M) - 4)
     623                 :            :          */
     624                 :            :         const uint32_t freq_value =
     625                 :            :                 (uint32_t)((384ULL * frequency) / 15625) - 262144;
     626                 :            : 
     627                 :            : #if NRF_CLOCK_HAS_HFCLKAUDIO
     628                 :            :         nrf_clock_hfclkaudio_config_set(NRF_CLOCK, freq_value);
     629                 :            : #else
     630                 :            : #error "hfclkaudio-frequency specified but HFCLKAUDIO clock is not present."
     631                 :            : #endif /* NRF_CLOCK_HAS_HFCLKAUDIO */
     632                 :            : #endif
     633                 :          1 : }
     634                 :            : 
     635                 :          1 : static int clk_init(const struct device *dev)
     636                 :            : {
     637                 :            :         nrfx_err_t nrfx_err;
     638                 :            :         int err;
     639                 :            :         static const struct onoff_transitions transitions = {
     640                 :            :                 .start = onoff_start,
     641                 :            :                 .stop = onoff_stop
     642                 :            :         };
     643                 :            : 
     644                 :          1 :         IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
     645                 :            :                     nrfx_isr, nrfx_power_clock_irq_handler, 0);
     646                 :            : 
     647                 :          1 :         nrfx_err = nrfx_clock_init(clock_event_handler);
     648         [ -  + ]:          1 :         if (nrfx_err != NRFX_SUCCESS) {
     649                 :          0 :                 return -EIO;
     650                 :            :         }
     651                 :            : 
     652                 :          1 :         hfclkaudio_init();
     653                 :            : 
     654                 :            :         if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION)) {
     655                 :            :                 struct nrf_clock_control_data *data = dev->data;
     656                 :            : 
     657                 :            :                 z_nrf_clock_calibration_init(data->mgr);
     658                 :            :         }
     659                 :            : 
     660                 :          1 :         nrfx_clock_enable();
     661                 :            : 
     662         [ +  + ]:          5 :         for (enum clock_control_nrf_type i = 0;
     663                 :          4 :                 i < CLOCK_CONTROL_NRF_TYPE_COUNT; i++) {
     664                 :            :                 struct nrf_clock_control_sub_data *subdata =
     665                 :          4 :                                                 get_sub_data(dev, i);
     666                 :            : 
     667                 :          4 :                 err = onoff_manager_init(get_onoff_manager(dev, i),
     668                 :            :                                          &transitions);
     669         [ -  + ]:          4 :                 if (err < 0) {
     670                 :          0 :                         return err;
     671                 :            :                 }
     672                 :            : 
     673                 :          4 :                 subdata->flags = CLOCK_CONTROL_STATUS_OFF;
     674                 :            :         }
     675                 :            : 
     676                 :          1 :         return 0;
     677                 :            : }
     678                 :            : 
     679                 :            : static const struct clock_control_driver_api clock_control_api = {
     680                 :            :         .on = api_blocking_start,
     681                 :            :         .off = api_stop,
     682                 :            :         .async_on = api_start,
     683                 :            :         .get_status = get_status,
     684                 :            : };
     685                 :            : 
     686                 :            : static struct nrf_clock_control_data data;
     687                 :            : 
     688                 :            : static const struct nrf_clock_control_config config = {
     689                 :            :         .subsys = {
     690                 :            :                 [CLOCK_CONTROL_NRF_TYPE_HFCLK] = {
     691                 :            :                         .start = generic_hfclk_start,
     692                 :            :                         .stop = generic_hfclk_stop,
     693                 :            :                         IF_ENABLED(CONFIG_LOG, (.name = "hfclk",))
     694                 :            :                 },
     695                 :            :                 [CLOCK_CONTROL_NRF_TYPE_LFCLK] = {
     696                 :            :                         .start = lfclk_start,
     697                 :            :                         .stop = lfclk_stop,
     698                 :            :                         IF_ENABLED(CONFIG_LOG, (.name = "lfclk",))
     699                 :            :                 },
     700                 :            : #if NRF_CLOCK_HAS_HFCLK192M
     701                 :            :                 [CLOCK_CONTROL_NRF_TYPE_HFCLK192M] = {
     702                 :            :                         .start = hfclk192m_start,
     703                 :            :                         .stop = hfclk192m_stop,
     704                 :            :                         IF_ENABLED(CONFIG_LOG, (.name = "hfclk192m",))
     705                 :            :                 },
     706                 :            : #endif
     707                 :            : #if NRF_CLOCK_HAS_HFCLKAUDIO
     708                 :            :                 [CLOCK_CONTROL_NRF_TYPE_HFCLKAUDIO] = {
     709                 :            :                         .start = hfclkaudio_start,
     710                 :            :                         .stop = hfclkaudio_stop,
     711                 :            :                         IF_ENABLED(CONFIG_LOG, (.name = "hfclkaudio",))
     712                 :            :                 },
     713                 :            : #endif
     714                 :            :         }
     715                 :            : };
     716                 :            : 
     717                 :            : DEVICE_DT_DEFINE(DT_NODELABEL(clock), clk_init, NULL,
     718                 :            :                  &data, &config,
     719                 :            :                  PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
     720                 :            :                  &clock_control_api);
     721                 :            : 
     722                 :          0 : static int cmd_status(const struct shell *shell, size_t argc, char **argv)
     723                 :            : {
     724                 :            :         nrf_clock_hfclk_t hfclk_src;
     725                 :            :         bool hf_status;
     726                 :          0 :         bool lf_status = nrfx_clock_is_running(NRF_CLOCK_DOMAIN_LFCLK, NULL);
     727                 :            :         struct onoff_manager *hf_mgr =
     728                 :          0 :                                 get_onoff_manager(CLOCK_DEVICE,
     729                 :            :                                                   CLOCK_CONTROL_NRF_TYPE_HFCLK);
     730                 :            :         struct onoff_manager *lf_mgr =
     731                 :          0 :                                 get_onoff_manager(CLOCK_DEVICE,
     732                 :            :                                                   CLOCK_CONTROL_NRF_TYPE_LFCLK);
     733                 :            :         uint32_t abs_start, abs_stop;
     734                 :          0 :         int key = irq_lock();
     735                 :          0 :         uint64_t now = k_uptime_get();
     736                 :            : 
     737                 :          0 :         (void)nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, (void *)&hfclk_src);
     738                 :          0 :         hf_status = (hfclk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY);
     739                 :            : 
     740                 :          0 :         abs_start = hf_start_tstamp;
     741                 :          0 :         abs_stop = hf_stop_tstamp;
     742                 :          0 :         irq_unlock(key);
     743                 :            : 
     744                 :          0 :         shell_print(shell, "HF clock:");
     745         [ #  # ]:          0 :         shell_print(shell, "\t- %srunning (users: %u)",
     746                 :            :                         hf_status ? "" : "not ", hf_mgr->refs);
     747                 :          0 :         shell_print(shell, "\t- last start: %u ms (%u ms ago)",
     748                 :            :                         (uint32_t)abs_start, (uint32_t)(now - abs_start));
     749                 :          0 :         shell_print(shell, "\t- last stop: %u ms (%u ms ago)",
     750                 :            :                         (uint32_t)abs_stop, (uint32_t)(now - abs_stop));
     751                 :          0 :         shell_print(shell, "LF clock:");
     752         [ #  # ]:          0 :         shell_print(shell, "\t- %srunning (users: %u)",
     753                 :            :                         lf_status ? "" : "not ", lf_mgr->refs);
     754                 :            : 
     755                 :          0 :         return 0;
     756                 :            : }
     757                 :            : 
     758                 :            : SHELL_STATIC_SUBCMD_SET_CREATE(subcmds,
     759                 :            :         SHELL_CMD_ARG(status, NULL, "Status", cmd_status, 1, 0),
     760                 :            :         SHELL_SUBCMD_SET_END
     761                 :            : );
     762                 :            : 
     763                 :            : SHELL_COND_CMD_REGISTER(CONFIG_CLOCK_CONTROL_NRF_SHELL,
     764                 :            :                         nrf_clock_control, &subcmds,
     765                 :            :                         "Clock control commands",
     766                 :            :                         cmd_status);

Generated by: LCOV version 1.14