text: /*
   * Copyright (c) 2016-2017 Nordic Semiconductor ASA
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  #include <soc.h>
  #include <clock_control.h>
  #include <system_timer.h>
  #include <drivers/clock_control/nrf5_clock_control.h>
  #include <sys_clock.h>
  
  /*
   * Convenience defines.
   */
  #define SYS_CLOCK_RTC          NRF_RTC1
  #define RTC_COUNTER            SYS_CLOCK_RTC->COUNTER
  #define RTC_CC_VALUE           SYS_CLOCK_RTC->CC[0]
  #define RTC_CC_EVENT           SYS_CLOCK_RTC->EVENTS_COMPARE[0]
  
  /* Minimum delta between current counter and CC register that the RTC is able
   * to handle
   */
  #define RTC_MIN_DELTA          2
  #define RTC_MASK               0x00FFFFFF
  /* Maximum difference for RTC counter values used. Half the maximum value is
   * selected to be able to detect overflow (a negative value has the same
   * representation as a large positive value).
   */
  #define RTC_HALF               (RTC_MASK / 2)
  
  /*
   * rtc_past holds the value of RTC_COUNTER at the time the last sys tick was
   * announced, in RTC ticks. It is therefore always a multiple of
   * sys_clock_hw_cycles_per_tick.
   */
  static u32_t rtc_past;
  
  #ifdef CONFIG_TICKLESS_IDLE
  /*
   * Holds the maximum sys ticks the kernel expects to see in the next
   * _sys_clock_tick_announce().
   */
  static u32_t expected_sys_ticks;
  #endif /* CONFIG_TICKLESS_IDLE */
  
  #ifdef CONFIG_TICKLESS_KERNEL
  s32_t _get_max_clock_time(void);
  #endif /* CONFIG_TICKLESS_KERNEL */
  
  /*
   * Set RTC Counter Compare (CC) register to a given value in RTC ticks.
   */
  static void rtc_compare_set(u32_t rtc_ticks)
  {
  	u32_t rtc_now;
  
  	/* Try to set CC value. We assume the procedure is always successful. */
  	RTC_CC_VALUE = rtc_ticks;
  	rtc_now = RTC_COUNTER;
  
  	/* The following checks if the CC register was set to a valid value.
  	 * The first test checks if the distance between the current RTC counter
  	 * and the value (in the future) set in the CC register is too small to
  	 * guarantee a compare event being triggered.
  	 * The second test checks if the current RTC counter is higher than the
  	 * value written to the CC register, i.e. the CC value is in the past,
  	 * by checking if the unsigned subtraction wraps around.
  	 * If either of the above are true then instead of waiting for the CC
  	 * event to trigger in the form of an interrupt, trigger it directly
  	 * using the NVIC.
  	 */
  	if ((((rtc_ticks - rtc_now) & RTC_MASK) < RTC_MIN_DELTA) ||
  	    (((rtc_ticks - rtc_now) & RTC_MASK) > RTC_HALF)) {
  		NVIC_SetPendingIRQ(NRF5_IRQ_RTC1_IRQn);
  	}
  }
  #ifndef CONFIG_TICKLESS_KERNEL
  /*
   * @brief Announces the number of sys ticks, if any, that have passed since the
   * last announcement, and programs the RTC to trigger the interrupt on the next
   * sys tick.
   *
   * This function is not reentrant. It is called from:
   *
   * * _timer_idle_exit(), which in turn is called with interrupts disabled when
   * an interrupt fires.
   * * rtc1_nrf5_isr(), which runs with interrupts enabled but at that time the
   * device cannot be idle and hence _timer_idle_exit() cannot be called.
   *
   * Since this function can be preempted, we need to take some provisions to
   * announce all expected sys ticks that have passed.
   *
   */
  static void rtc_announce_set_next(void)
  {
  	u32_t rtc_now, rtc_elapsed, sys_elapsed;
  
  	/* Read the RTC counter one single time in the beginning, so that an
  	 * increase in the counter during this procedure leads to no race
  	 * conditions.
  	 */
  	rtc_now = RTC_COUNTER;
  
  	/* Calculate how many RTC ticks elapsed since the last sys tick. */
  	rtc_elapsed = (rtc_now - rtc_past) & RTC_MASK;
  
  	/* If no sys ticks have elapsed, there is no point in incrementing the
  	 * counters or announcing it.
  	 */
  	if (rtc_elapsed >= sys_clock_hw_cycles_per_tick) {
  #ifdef CONFIG_TICKLESS_IDLE
  		/* Calculate how many sys ticks elapsed since the last sys tick
  		 * and notify the kernel if necessary.
  		 */
  		sys_elapsed = rtc_elapsed / sys_clock_hw_cycles_per_tick;
  
  		if (sys_elapsed > expected_sys_ticks) {
  			/* Never announce more sys ticks than the kernel asked
  			 * to be idle for. The remainder will be announced when
  			 * the RTC ISR runs after rtc_compare_set() is called
  			 * after the first announcement.
  			 */
  			sys_elapsed = expected_sys_ticks;
  		}
  #else
  		/* Never announce more than one sys tick if tickless idle is not
  		 * configured.
  		 */
  		sys_elapsed = 1;
  #endif /* CONFIG_TICKLESS_IDLE */
  
  		/* Store RTC_COUNTER floored to the last sys tick. This is
  		 * done, so that ISR can properly calculate that 1 sys tick
  		 * has passed.
  		 */
  		rtc_past = (rtc_past +
  				(sys_elapsed * sys_clock_hw_cycles_per_tick)
  			   ) & RTC_MASK;
  
  		_sys_idle_elapsed_ticks = sys_elapsed;
  		_sys_clock_tick_announce();
  	}
  
  	/* Set the RTC to the next sys tick */
  	rtc_compare_set(rtc_past + sys_clock_hw_cycles_per_tick);
  }
  #endif
  
  #ifdef CONFIG_TICKLESS_IDLE
  /**
   * @brief Place system timer into idle state.
   *
   * Re-program the timer to enter into the idle state for the given number of
   * sys ticks, counted from the previous sys tick. The timer will fire in the
   * number of sys ticks supplied or the maximum number of sys ticks (converted
   * to RTC ticks) that can be programmed into the hardware.
   *
   * This will only be called from idle context, with IRQs disabled.
   *
   * A value of -1 will result in the maximum number of sys ticks.
   *
   * Example 1: Idle sleep is entered:
   *
   * sys tick timeline:       (1)    (2)    (3)    (4)    (5)    (6)
   * rtc tick timeline : 0----100----200----300----400----500----600
   *                               ******************
   *                              150
   *
   * a) The last sys tick was announced at 100
   * b) The idle context enters sleep at 150, between sys tick 1 and 2, with
   * sys_ticks = 3.
   * c) The RTC is programmed to fire at sys tick 1 + 3 = 4 (RTC tick 400)
   *
   * @return N/A
   */
  void _timer_idle_enter(s32_t sys_ticks)
  {
  #ifdef CONFIG_TICKLESS_KERNEL
  	if (sys_ticks != K_FOREVER) {
  		/* Need to reprograme timer if current program is smaller*/
  		if (sys_ticks > expected_sys_ticks) {
  			_set_time(sys_ticks);
  		}
  	} else {
  		expected_sys_ticks = 0;
  		/* Set time to largest possile RTC Tick*/
  		_set_time(_get_max_clock_time());
  	}
  #else
  	/* Restrict ticks to max supported by RTC without risking overflow*/
  	if ((sys_ticks < 0) ||
  		(sys_ticks > (RTC_HALF / sys_clock_hw_cycles_per_tick))) {
  		sys_ticks = RTC_HALF / sys_clock_hw_cycles_per_tick;
  	}
  
  	expected_sys_ticks = sys_ticks;
  
  	/* If ticks is 0, the RTC interrupt handler will be set pending
  	 * immediately, meaning that we will not go to sleep.
  	 */
  	rtc_compare_set(rtc_past + (sys_ticks * sys_clock_hw_cycles_per_tick));
  #endif
  }
  
  
  #ifdef CONFIG_TICKLESS_KERNEL
  
  /**
   * @brief provides total systicks programmed.
   *
   * returns : total number of sys ticks programmed.
   */
  
  u32_t _get_program_time(void)
  {
  	return expected_sys_ticks;
  }
  
  /**
   * @brief provides total systicks remaining since last programming of RTC.
   *
   * returns : total number of sys ticks remaining since last RTC programming.
   */
  
  u32_t _get_remaining_program_time(void)
  {
  
  	if (!expected_sys_ticks) {
  		return 0;
  	}
  
  	return (expected_sys_ticks - _get_elapsed_program_time());
  }
  
  /**
   * @brief provides total systicks passed since last programming of RTC.
   *
   * returns : total number of sys ticks passed since last RTC programming.
   */
  
  u32_t _get_elapsed_program_time(void)
  {
  	u32_t rtc_now, rtc_prev, rtc_elapsed;
  
  	if (!expected_sys_ticks) {
  		return 0;
  	}
  
  	rtc_now = RTC_COUNTER;
  
  	/* Discard value of  RTC_COUNTER read at LFCLK transition */
  	do {
  		/* Number of RTC cycles passed since last RTC Programing*/
  		rtc_elapsed = (rtc_now - rtc_past) & RTC_MASK;
  		rtc_prev = rtc_now;
  		rtc_now = RTC_COUNTER;
  	} while (rtc_prev != rtc_now);
  
  	/*Convert number of Machine cycles to SYS TICS*/
  	return (rtc_elapsed / sys_clock_hw_cycles_per_tick);
  }
  
  
  /**
   * @brief Sets interrupt for rtc compare value for systick time.
   *
   * This Function does following:-
   * 1. Updates expected_sys_ticks equal to time.
   * 2. Update kernel book keeping for time passed since device bootup.
   * 3. Calls routine to set rtc interrupt.
   */
  
  void _set_time(u32_t time)
  {
  	if (!time) {
  		expected_sys_ticks = 0;
  		return;
  	}
  
  	/* Update expected_sys_ticls to time to programe*/
  	expected_sys_ticks = time;
  	_sys_clock_tick_count = _get_elapsed_clock_time();
  	/* Update rtc_past to track rtc timer count*/
  	rtc_past = (_sys_clock_tick_count * sys_clock_hw_cycles_per_tick) & RTC_MASK;
  
  	expected_sys_ticks = expected_sys_ticks > _get_max_clock_time() ?
  				_get_max_clock_time() : expected_sys_ticks;
  
  	/* Programe RTC compare register to generate interrupt*/
  	rtc_compare_set(rtc_past +
  			(expected_sys_ticks * sys_clock_hw_cycles_per_tick));
  
  }
  
  /**
   * @brief provides time remaining to reach rtc count overflow.
   *
   * This function returns how many sys RTC remaining for rtc to overflow.
   * This will be required when we will program RTC compare value to maximum
   * possible value.
   *
   * returns : difference between current systick and Maximum possible systick.
   */
  s32_t _get_max_clock_time(void)
  {
  	u32_t rtc_now, rtc_prev, rtc_away, sys_away = 0;
  
  	rtc_now = RTC_COUNTER;
  	/* Discard value of  RTC_COUNTER read at LFCLK transition */
  	do {
  		rtc_away = (RTC_MASK - rtc_now);
  		rtc_away = rtc_away > RTC_HALF ? RTC_HALF : rtc_away;
  		rtc_prev = rtc_now;
  		/* Calculate time to programe into RTC*/
  		rtc_now = RTC_COUNTER;
  	} while (rtc_now != rtc_prev);
  
  	/* Convert RTC Ticks to SYS TICKS*/
  	if (rtc_away >= sys_clock_hw_cycles_per_tick) {
  		sys_away = rtc_away / sys_clock_hw_cycles_per_tick;
  	}
  	return sys_away;
  }
  
  /**
   * @brief Enable sys Clock.
   *
   * This is used to program RTC clock to maximum Clock time in case Clock to
   * remain On.
   */
  void _enable_sys_clock(void)
  {
  	if (!expected_sys_ticks) {
  		/* Programe sys tick to Maximum possible value*/
  		_set_time(_get_max_clock_time());
  	}
  }
  
  /**
   * @brief provides total systicks passed since device bootup.
   *
   * returns : total number of sys ticks passed since device bootup.
   */
  
  u64_t _get_elapsed_clock_time(void)
  {
  	u64_t elapsed;
  	u32_t rtc_now, rtc_elapsed, rtc_prev, sys_elapsed;
  
  	rtc_now = RTC_COUNTER;
  
  	/* Discard value of  RTC_COUNTER read at LFCLK transition */
  	do {
  		/* Calculate number of rtc cycles elapsed since RTC programing*/
  		rtc_elapsed = (rtc_now - rtc_past) & RTC_MASK;
  		elapsed = _sys_clock_tick_count;
  		rtc_prev = rtc_now;
  		rtc_now = RTC_COUNTER;
  	} while (rtc_now != rtc_prev);
  
  	if (rtc_elapsed >= sys_clock_hw_cycles_per_tick) {
  		/* Convert RTC cycles to SYS TICKS*/
  		sys_elapsed = rtc_elapsed / sys_clock_hw_cycles_per_tick;
  		/* Update total number of SYS_TICKS passed*/
  		elapsed += sys_elapsed;
  	}
  	return elapsed;
  }
  #endif
  
  
  /**
   *
   * @brief Handling of tickless idle when interrupted
   *
   * The function will be called by _sys_power_save_idle_exit(), called from
   * _arch_isr_direct_pm() for 'direct' interrupts, or from _isr_wrapper for
   * regular ones, which is called on every IRQ handler if the device was
   * idle, and optionally called when a 'direct' IRQ handler executes if the
   * device was idle.
   *
   * Example 1: Idle sleep is interrupted before time:
   *
   * sys tick timeline:       (1)    (2)    (3)    (4)    (5)    (6)
   * rtc tick timeline : 0----100----200----300----400----500----600
   *                               **************!***
   *                              150           350
   *
   * Assume that _timer_idle_enter() is called at 150 (1) to sleep for 3
   * sys ticks. The last sys tick was announced at 100.
   *
   * On wakeup (non-RTC IRQ at 350):
   *
   * a) Notify how many sys ticks have passed, i.e., 350 - 150 / 100 = 2.
   * b) Schedule next sys tick at 400.
   *
   */
  void _timer_idle_exit(void)
  {
  #ifdef CONFIG_TICKLESS_KERNEL
  	if (!expected_sys_ticks && _sys_clock_always_on) {
  		_set_time(_get_max_clock_time());
  	}
  #else
  	/* Clear the event flag and interrupt in case we woke up on the RTC
  	 * interrupt. No need to run the RTC ISR since everything that needs
  	 * to run in the ISR will be done in this call.
  	 */
  	RTC_CC_EVENT = 0;
  	NVIC_ClearPendingIRQ(NRF5_IRQ_RTC1_IRQn);
  
  	rtc_announce_set_next();
  
  	/* After exiting idle, the kernel no longer expects more than one sys
  	 * ticks to have passed when _sys_clock_tick_announce() is called.
  	 */
  	expected_sys_ticks = 1;
  #endif
  }
  #endif /* CONFIG_TICKLESS_IDLE */
  
  /*
   * @brief Announces the number of sys ticks that have passed since the last
   * announcement, if any, and programs the RTC to trigger the interrupt on the
   * next sys tick.
   *
   * The ISR is set pending due to a regular sys tick and after exiting idle mode
   * as scheduled.
   *
   * Since this ISR can be preempted, we need to take some provisions to announce
   * all expected sys ticks that have passed.
   *
   * Consider the following example:
   *
   * sys tick timeline:       (1)    (2)    (3)    (4)    (5)    (6)
   * rtc tick timeline : 0----100----200----300----400----500----600
   *                                         !**********
   *                                                  450
   *
   * The last sys tick was anounced at 200, i.e, rtc_past = 200. The ISR is
   * executed at the next sys tick, i.e. 300. The following sys tick is due at
   * 400. However, the ISR is preempted for a number of sys ticks, until 450 in
   * this example. The ISR will then announce the number of sys ticks it was
   * delayed (2), and schedule the next sys tick (5) at 500.
   */
  void rtc1_nrf5_isr(void *arg)
  {
  
  	ARG_UNUSED(arg);
  	RTC_CC_EVENT = 0;
  
  #ifdef CONFIG_EXECUTION_BENCHMARKING
  	extern void read_timer_start_of_tick_handler(void);
  	read_timer_start_of_tick_handler();
  #endif
  
  #ifdef CONFIG_TICKLESS_KERNEL
  	_sys_idle_elapsed_ticks = expected_sys_ticks;
  	/* Initialize expected sys tick,
  	 * It will be later updated based on next timeout.
  	 */
  	expected_sys_ticks = 0;
  	/* Anounce elapsed of _sys_idle_elapsed_ticks systicks*/
  	_sys_clock_tick_announce();
  #else
  	rtc_announce_set_next();
  #endif
  
  #ifdef CONFIG_EXECUTION_BENCHMARKING
  	extern void read_timer_end_of_tick_handler(void);
  	read_timer_end_of_tick_handler();
  #endif
  
  }
  
  int _sys_clock_driver_init(struct device *device)
  {
  	struct device *clock;
  
  	ARG_UNUSED(device);
  
  	clock = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_K32SRC_DRV_NAME);
  	if (!clock) {
  		return -1;
  	}
  
  	clock_control_on(clock, (void *)CLOCK_CONTROL_NRF5_K32SRC);
  
  	rtc_past = 0;
  
  #ifdef CONFIG_TICKLESS_IDLE
  	expected_sys_ticks = 1;
  #endif /* CONFIG_TICKLESS_IDLE */
  
  	/* TODO: replace with counter driver to access RTC */
  	SYS_CLOCK_RTC->PRESCALER = 0;
  	SYS_CLOCK_RTC->CC[0] = sys_clock_hw_cycles_per_tick;
  	SYS_CLOCK_RTC->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
  	SYS_CLOCK_RTC->INTENSET = RTC_INTENSET_COMPARE0_Msk;
  
  	/* Clear the event flag and possible pending interrupt */
  	RTC_CC_EVENT = 0;
  	NVIC_ClearPendingIRQ(NRF5_IRQ_RTC1_IRQn);
  
  	IRQ_CONNECT(NRF5_IRQ_RTC1_IRQn, 1, rtc1_nrf5_isr, 0, 0);
  	irq_enable(NRF5_IRQ_RTC1_IRQn);
  
  	SYS_CLOCK_RTC->TASKS_CLEAR = 1;
  	SYS_CLOCK_RTC->TASKS_START = 1;
  
  	return 0;
  }
  
  u32_t _timer_cycle_get_32(void)
  {
  	u32_t elapsed_cycles;
  	u32_t sys_clock_tick_count;
  	u32_t rtc_prev;
  	u32_t rtc_now;
  
  	rtc_now = RTC_COUNTER;
  	/* Discard value of  RTC_COUNTER read at LFCLK transition */
  	do {
  		sys_clock_tick_count = _sys_clock_tick_count;
  		elapsed_cycles = (rtc_now - (sys_clock_tick_count *
  					     sys_clock_hw_cycles_per_tick)) &
  				 RTC_MASK;
  		rtc_prev = rtc_now;
  		rtc_now = RTC_COUNTER;
  	} while (rtc_now != rtc_prev);
  
  	return (sys_clock_tick_count * sys_clock_hw_cycles_per_tick) +
  	       elapsed_cycles;
  }
  
  #ifdef CONFIG_SYSTEM_CLOCK_DISABLE
  /**
   *
   * @brief Stop announcing sys ticks into the kernel
   *
   * This routine disables the RTC1 so that timer interrupts are no
   * longer delivered.
   *
   * @return N/A
   */
  void sys_clock_disable(void)
  {
  	unsigned int key;
  
  	key = irq_lock();
  
  	irq_disable(NRF5_IRQ_RTC1_IRQn);
  
  	SYS_CLOCK_RTC->EVTENCLR = RTC_EVTENCLR_COMPARE0_Msk;
  	SYS_CLOCK_RTC->INTENCLR = RTC_INTENCLR_COMPARE0_Msk;
  
  	SYS_CLOCK_RTC->TASKS_STOP = 1;
  	SYS_CLOCK_RTC->TASKS_CLEAR = 1;
  
  	irq_unlock(key);
  
  	/* TODO: turn off (release) 32 KHz clock source.
  	 * Turning off of 32 KHz clock source is not implemented in clock
  	 * driver.
  	 */
  }
  #endif /* CONFIG_SYSTEM_CLOCK_DISABLE */
  