1 /* 2 * Copyright (c) 2017 Oticon A/S 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 #include "NRF_CLOCK.h" 7 #include <string.h> 8 #include <stdint.h> 9 #include "time_machine_if.h" 10 #include "NRF_HW_model_top.h" 11 #include "NRF_PPI.h" 12 #include "NRF_RTC.h" 13 #include "irq_ctrl.h" 14 #include "irq_sources.h" 15 16 /* 17 * CLOCK — Clock control 18 * http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52840.ps/clock.html?cp=2_0_0_16#frontpage_clock 19 */ 20 21 //Note: We assume the 32.768 KHz clock does not drift relative to the 64MHz one 22 // which would only happen if they had the same source or there was a tracking 23 // and adjustment loop of one based on the other 24 25 NRF_CLOCK_Type NRF_CLOCK_regs; 26 static uint32_t CLOCK_INTEN = 0; //interrupt enable 27 28 bs_time_t Timer_CLOCK_LF = TIME_NEVER; //LF clock timer 29 bs_time_t Timer_CLOCK_HF = TIME_NEVER; 30 static bool LF_Clock_started = false; 31 32 static enum { Stopped, Starting, Started, Stopping} HF_Clock_state = Stopped; 33 34 uint64_t next_lf_tick = 0; // when will the LF clock tick with 9 bits per us resolution 35 // note that this will wrap at ((1e-6/2^9)*2^64)/3600/24/365 ~= 1142 years 36 //=> this model will break after 1142 years of simulated time 37 nrf_clock_init()38void nrf_clock_init(){ 39 memset(&NRF_CLOCK_regs, 0, sizeof(NRF_CLOCK_regs)); 40 LF_Clock_started = false; 41 HF_Clock_state = Stopped; 42 Timer_CLOCK_LF = TIME_NEVER; 43 Timer_CLOCK_HF = TIME_NEVER; 44 } 45 nrf_clock_clean_up()46void nrf_clock_clean_up(){ 47 48 } 49 nrf_clock_TASKS_LFCLKSTART()50void nrf_clock_TASKS_LFCLKSTART(){ 51 NRF_CLOCK_regs.LFCLKSRCCOPY = NRF_CLOCK_regs.LFCLKSRC & CLOCK_LFCLKSRC_SRC_Msk; 52 NRF_CLOCK_regs.LFCLKRUN = CLOCK_LFCLKRUN_STATUS_Msk; 53 54 Timer_CLOCK_LF = tm_get_hw_time(); //we assume the clock is ready in 1 delta 55 //I guess we could assume some delay here.. but there is little need for this in this controller 56 nrf_hw_find_next_timer_to_trigger(); 57 58 } 59 nrf_clock_TASKS_HFCLKSTART()60void nrf_clock_TASKS_HFCLKSTART(){ 61 if ( ( HF_Clock_state == Stopped ) || ( HF_Clock_state == Stopping ) ) { 62 HF_Clock_state = Starting; 63 NRF_CLOCK_regs.HFCLKRUN = CLOCK_HFCLKRUN_STATUS_Msk; 64 Timer_CLOCK_HF = tm_get_hw_time(); //we assume the clock is ready in 1 delta 65 //I guess we could assume some delay here.. but there is little need for this in this controller 66 nrf_hw_find_next_timer_to_trigger(); 67 } 68 } 69 nrf_clock_TASKS_HFCLKSTOP()70void nrf_clock_TASKS_HFCLKSTOP(){ 71 if ( ( HF_Clock_state == Started ) || ( HF_Clock_state == Starting ) ) { 72 NRF_CLOCK_regs.HFCLKRUN = 0; 73 HF_Clock_state = Stopping; 74 Timer_CLOCK_HF = tm_get_hw_time(); //we assume the clock is ready in 1 delta 75 //I guess we could assume some delay here.. but there is little need for this in this controller 76 nrf_hw_find_next_timer_to_trigger(); 77 } 78 } 79 nrf_clock_reqw_sideeffects_INTENSET()80void nrf_clock_reqw_sideeffects_INTENSET(){ 81 if ( NRF_CLOCK_regs.INTENSET ){ 82 CLOCK_INTEN |= NRF_CLOCK_regs.INTENSET; 83 NRF_CLOCK_regs.INTENSET = CLOCK_INTEN; 84 } 85 } 86 nrf_clock_reqw_sideeffects_INTENCLR()87void nrf_clock_reqw_sideeffects_INTENCLR(){ 88 if ( NRF_CLOCK_regs.INTENCLR ){ 89 CLOCK_INTEN &= ~NRF_CLOCK_regs.INTENCLR; 90 NRF_CLOCK_regs.INTENSET = CLOCK_INTEN; 91 NRF_CLOCK_regs.INTENCLR = 0; 92 } 93 } 94 nrf_clock_reqw_sideeffects_TASKS_LFCLKSTART()95void nrf_clock_reqw_sideeffects_TASKS_LFCLKSTART(){ 96 if ( NRF_CLOCK_regs.TASKS_LFCLKSTART ){ 97 NRF_CLOCK_regs.TASKS_LFCLKSTART = 0; 98 nrf_clock_TASKS_LFCLKSTART(); 99 } 100 } 101 nrf_clock_reqw_sideeffects_TASKS_LFCLKSTOP()102void nrf_clock_reqw_sideeffects_TASKS_LFCLKSTOP() { 103 // There is no effect of turning the clock off that is actually modeled 104 if ( NRF_CLOCK_regs.TASKS_LFCLKSTOP ){ 105 NRF_CLOCK_regs.LFCLKRUN = 0; 106 } 107 } 108 nrf_clock_reqw_sideeffects_TASKS_HFCLKSTART()109void nrf_clock_reqw_sideeffects_TASKS_HFCLKSTART(){ 110 if ( NRF_CLOCK_regs.TASKS_HFCLKSTART ){ 111 NRF_CLOCK_regs.TASKS_HFCLKSTART = 0; 112 nrf_clock_TASKS_HFCLKSTART(); 113 } 114 } 115 nrf_clock_reqw_sideeffects_TASKS_HFCLKSTOP()116void nrf_clock_reqw_sideeffects_TASKS_HFCLKSTOP(){ 117 if ( NRF_CLOCK_regs.TASKS_HFCLKSTOP ){ 118 NRF_CLOCK_regs.TASKS_HFCLKSTOP = 0; 119 nrf_clock_TASKS_HFCLKSTOP(); 120 } 121 } 122 nrf_clock_regw_sideeffects()123void nrf_clock_regw_sideeffects(){ 124 125 nrf_clock_reqw_sideeffects_INTENSET(); 126 127 nrf_clock_reqw_sideeffects_INTENCLR(); 128 129 nrf_clock_reqw_sideeffects_TASKS_LFCLKSTART(); 130 131 nrf_clock_reqw_sideeffects_TASKS_HFCLKSTART(); 132 } 133 nrf_clock_LFTimer_triggered()134void nrf_clock_LFTimer_triggered(){ 135 //We just assume the enable comes with the first tick of the clock 136 137 if ( LF_Clock_started == false ){ 138 LF_Clock_started = true; 139 140 NRF_CLOCK_regs.LFCLKSTAT = CLOCK_LFCLKSTAT_STATE_Msk 141 | (NRF_CLOCK_regs.LFCLKSRCCOPY << CLOCK_LFCLKSTAT_SRC_Pos); 142 143 NRF_CLOCK_regs.EVENTS_LFCLKSTARTED = 1; 144 nrf_ppi_event(CLOCK_EVENTS_LFCLKSTARTED); 145 if ( CLOCK_INTEN & CLOCK_INTENSET_LFCLKSTARTED_Msk ){ 146 hw_irq_ctrl_set_irq(NRF5_IRQ_POWER_CLOCK_IRQn); 147 } 148 149 nrf_rtc_notify_first_lf_tick(); 150 } 151 152 Timer_CLOCK_LF = TIME_NEVER; 153 nrf_hw_find_next_timer_to_trigger(); 154 } 155 nrf_clock_HFTimer_triggered()156void nrf_clock_HFTimer_triggered(){ 157 if ( HF_Clock_state == Starting ){ 158 HF_Clock_state = Started; 159 160 NRF_CLOCK_regs.HFCLKSTAT = CLOCK_HFCLKSTAT_STATE_Msk 161 | ( CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos); 162 163 NRF_CLOCK_regs.EVENTS_HFCLKSTARTED = 1; 164 nrf_ppi_event(CLOCK_EVENTS_HFCLKSTARTED); 165 if ( CLOCK_INTEN & CLOCK_INTENSET_HFCLKSTARTED_Msk ){ 166 hw_irq_ctrl_set_irq(NRF5_IRQ_POWER_CLOCK_IRQn); 167 } 168 169 } else if ( HF_Clock_state == Stopping ){ 170 HF_Clock_state = Stopped; 171 NRF_CLOCK_regs.HFCLKSTAT = 0; 172 } 173 174 Timer_CLOCK_HF = TIME_NEVER; 175 nrf_hw_find_next_timer_to_trigger(); 176 } 177