drivers: timer: add RTC support as system clock for CC13X2/CC26X2

Add RTC timer driver for CC13X2/CC26X2, and use it instead of systick
as system clock. It is necessary to use this timer for power
management support, so that the system can exit from deep sleep upon
expiry of timeouts.

Signed-off-by: Vincent Wan <vincent.wan@linaro.org>
This commit is contained in:
Vincent Wan 2019-08-20 09:58:04 -07:00 committed by Kumar Gala
commit aeb8d017b5
10 changed files with 297 additions and 3 deletions

View file

@ -82,3 +82,7 @@
cs-pin = <11>;
cs-gpios = <&gpio0 11 0>;
};
&rtc {
status = "okay";
};

View file

@ -7,7 +7,6 @@
CONFIG_ARM=y
CONFIG_SOC_SERIES_CC13X2_CC26X2=y
CONFIG_SOC_CC1352R=y
CONFIG_CORTEX_M_SYSTICK=y
CONFIG_BOARD_CC1352R1_LAUNCHXL=y
CONFIG_CC13X2_CC26X2_BOOTLOADER_ENABLE=y

View file

@ -82,3 +82,7 @@
cs-pin = <11>;
cs-gpios = <&gpio0 11 0>;
};
&rtc {
status = "okay";
};

View file

@ -7,7 +7,6 @@
CONFIG_ARM=y
CONFIG_SOC_SERIES_CC13X2_CC26X2=y
CONFIG_SOC_CC2652R=y
CONFIG_CORTEX_M_SYSTICK=y
CONFIG_BOARD_CC26X2R1_LAUNCHXL=y
CONFIG_CC13X2_CC26X2_BOOTLOADER_ENABLE=y

View file

@ -16,3 +16,4 @@ zephyr_sources_if_kconfig( sam0_rtc_timer.c)
zephyr_sources_if_kconfig( litex_timer.c)
zephyr_sources_if_kconfig( mchp_xec_rtos_timer.c)
zephyr_sources_if_kconfig( xlnx_psttc_timer.c)
zephyr_sources_if_kconfig( cc13x2_cc26x2_rtc_timer.c)

View file

@ -220,6 +220,15 @@ config MCHP_XEC_RTOS_TIMER
XEC series RTOS timer and provides the standard "system clock
driver" interfaces.
config CC13X2_CC26X2_RTC_TIMER
bool "TI SimpleLink CC13x2/CC26x2 RTC timer"
depends on SOC_SERIES_CC13X2_CC26X2
select TICKLESS_CAPABLE
help
This module implements a kernel device driver for the TI SimpleLink
CC13X2_CC26X2 series Real Time Counter and provides the standard
"system clock driver" interfaces.
config XLNX_PSTTC_TIMER
bool "Xilinx PS ttc timer support"
default y

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2019, Texas Instruments Incorporated
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* TI SimpleLink CC13X2/CC26X2 RTC-based system timer
*
* This system timer implementation supports both tickless and ticking modes.
* RTC counts continually in 64-bit mode and timeouts are
* scheduled using the RTC comparator. An interrupt is triggered whenever
* the comparator value set is reached.
*/
#include <soc.h>
#include <drivers/clock_control.h>
#include <drivers/timer/system_timer.h>
#include <sys_clock.h>
#include <driverlib/interrupt.h>
#include <driverlib/aon_rtc.h>
#include <driverlib/aon_event.h>
#define RTC_COUNTS_PER_SEC 0x100000000ULL
/* Number of counts per rtc timer cycle */
#define RTC_COUNTS_PER_CYCLE (RTC_COUNTS_PER_SEC / \
sys_clock_hw_cycles_per_sec())
/* Number of counts per system clock tick */
#define RTC_COUNTS_PER_TICK (RTC_COUNTS_PER_SEC / \
CONFIG_SYS_CLOCK_TICKS_PER_SEC)
/* Number of RTC cycles per system clock tick */
#define CYCLES_PER_TICK (sys_clock_hw_cycles_per_sec() / \
CONFIG_SYS_CLOCK_TICKS_PER_SEC)
/*
* Maximum number of ticks.
*/
#define MAX_TICKS (0x7FFFFFFFFFFFULL / RTC_COUNTS_PER_TICK)
/*
* Due to the nature of clock synchronization, the comparator cannot be set
* to a value that is too close to the current time. This constant defines
* a safe threshold for the comparator.
*/
#define COMPARE_MARGIN 6
/* RTC count of the last announce call, rounded down to tick boundary. */
static volatile u64_t rtc_last;
#ifdef CONFIG_TICKLESS_KERNEL
static struct k_spinlock lock;
#else
static u64_t nextThreshold = RTC_COUNTS_PER_TICK;
#endif /* CONFIG_TICKLESS_KERNEL */
static void setThreshold(u32_t next)
{
u32_t now;
unsigned int key;
key = irq_lock();
/* get the current RTC count corresponding to compare window */
now = AONRTCCurrentCompareValueGet();
/* if next is too soon, set at least one RTC tick in future */
/* assume next never be more than half the maximum 32 bit count value */
if ((next - now) > (u32_t)0x80000000) {
/* now is past next */
next = now + COMPARE_MARGIN;
} else if ((now + COMPARE_MARGIN - next) < (u32_t)0x80000000) {
if (next < now + COMPARE_MARGIN) {
next = now + COMPARE_MARGIN;
}
}
/* set next compare threshold in RTC */
AONRTCCompareValueSet(AON_RTC_CH0, next);
irq_unlock(key);
}
void rtc_isr(void *arg)
{
#ifndef CONFIG_TICKLESS_KERNEL
u64_t newThreshold;
u32_t next;
#else
u64_t ticks, currCount;
#endif
ARG_UNUSED(arg);
AONRTCEventClear(AON_RTC_CH0);
#ifdef CONFIG_TICKLESS_KERNEL
k_spinlock_key_t key = k_spin_lock(&lock);
currCount = (u64_t)AONRTCCurrent64BitValueGet();
ticks = (currCount - rtc_last) / RTC_COUNTS_PER_TICK;
rtc_last += ticks * RTC_COUNTS_PER_TICK;
k_spin_unlock(&lock, key);
z_clock_announce(ticks);
#else /* !CONFIG_TICKLESS_KERNEL */
/* calculate new 64-bit RTC count for next interrupt */
newThreshold = nextThreshold + RTC_COUNTS_PER_TICK;
next = (u32_t)((u64_t)newThreshold >> 16);
setThreshold(next);
nextThreshold = newThreshold;
rtc_last += RTC_COUNTS_PER_TICK;
z_clock_announce(1);
#endif /* CONFIG_TICKLESS_KERNEL */
}
static void initDevice(void)
{
AONRTCDisable();
AONRTCReset();
HWREG(AON_RTC_BASE + AON_RTC_O_SYNC) = 1;
/* read sync register to complete reset */
HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);
AONRTCEventClear(AON_RTC_CH0);
IntPendClear(INT_AON_RTC_COMB);
HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);
}
static void startDevice(void)
{
u32_t compare;
u64_t period;
unsigned int key;
key = irq_lock();
/* reset timer */
AONRTCReset();
AONRTCEventClear(AON_RTC_CH0);
IntPendClear(INT_AON_RTC_COMB);
/*
* set the compare register to one period.
* For a very small period round up to interrupt upon 4th tick in
* compare register
*/
period = RTC_COUNTS_PER_TICK;
if (period < 0x40000) {
compare = 0x4; /* 4 * 15.5us ~= 62us */
} else {
/* else, interrupt on first period expiration */
compare = period >> 16;
}
/* set the compare value at the RTC */
AONRTCCompareValueSet(AON_RTC_CH0, compare);
/* enable compare channel 0 */
AONEventMcuWakeUpSet(AON_EVENT_MCU_WU0, AON_EVENT_RTC0);
AONRTCChannelEnable(AON_RTC_CH0);
AONRTCCombinedEventConfig(AON_RTC_CH0);
/* start timer */
AONRTCEnable();
irq_unlock(key);
}
int z_clock_driver_init(struct device *device)
{
ARG_UNUSED(device);
rtc_last = 0U;
initDevice();
startDevice();
/* Enable RTC interrupt. */
IRQ_CONNECT(DT_INST_0_TI_CC13XX_CC26XX_RTC_IRQ_0,
DT_INST_0_TI_CC13XX_CC26XX_RTC_IRQ_0_PRIORITY,
rtc_isr, 0, 0);
irq_enable(DT_INST_0_TI_CC13XX_CC26XX_RTC_IRQ_0);
return 0;
}
void z_clock_set_timeout(s32_t ticks, bool idle)
{
ARG_UNUSED(idle);
#ifdef CONFIG_TICKLESS_KERNEL
ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t) MAX_TICKS), 0);
k_spinlock_key_t key = k_spin_lock(&lock);
/* Compute number of RTC cycles until the next timeout. */
u64_t count = AONRTCCurrent64BitValueGet();
u64_t timeout = ticks * RTC_COUNTS_PER_TICK +
(count - rtc_last);
/* Round to the nearest tick boundary. */
timeout = (timeout + RTC_COUNTS_PER_TICK - 1) / RTC_COUNTS_PER_TICK
* RTC_COUNTS_PER_TICK;
timeout += rtc_last;
/* Set the comparator */
setThreshold(timeout >> 16);
k_spin_unlock(&lock, key);
#endif /* CONFIG_TICKLESS_KERNEL */
}
u32_t z_clock_elapsed(void)
{
u32_t ret = (AONRTCCurrent64BitValueGet() - rtc_last) /
RTC_COUNTS_PER_TICK;
return ret;
}
u32_t z_timer_cycle_get_32(void)
{
return (AONRTCCurrent64BitValueGet() / RTC_COUNTS_PER_CYCLE)
& 0xFFFFFFFF;
}

View file

@ -113,6 +113,14 @@
status = "disabled";
label = "SPI_1";
};
rtc: rtc@40092000 {
compatible = "ti,cc13xx-cc26xx-rtc";
reg = <0x40092000 0x1000>;
interrupts = <4 0>; /* interrupt #20 = 4 + 16 */
status = "disabled";
label = "RTC";
};
};
};

View file

@ -0,0 +1,18 @@
#
# Copyright (c) 2019, Texas Instruments Incorporated
#
# SPDX-License-Identifier: Apache-2.0
#
title: TI SimpleLink CC13xx/CC26xx RTC
description: >
This binding gives a base representation of the TI SimpleLink CC13xx/CC26xx RTC
compatible: "ti,cc13xx-cc26xx-rtc"
include: rtc.yaml
properties:
reg:
required: true

View file

@ -15,7 +15,14 @@ config SOC_SERIES
config SYS_CLOCK_HW_CYCLES_PER_SEC
int
default 48000000
default 32768
# Note that when using the RTC as system clock, this needs to be 32768
# to reduce truncation errors from accumulating due to conversion to/from
# time, ticks, and HW cycles
config SYS_CLOCK_TICKS_PER_SEC
int
default 32768
config NUM_IRQS
int
@ -25,6 +32,9 @@ config TI_CCFG_PRESENT
bool
default y
config CC13X2_CC26X2_RTC_TIMER
default y
if PINMUX
config PINMUX_CC13XX_CC26XX