drivers: counter: Counter API implementation for nRF Series (RTC).

Shim for counter API using nrfx_rtc driver.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2018-06-28 09:30:04 +02:00 committed by Anas Nashif
commit da0d9bab2d
7 changed files with 338 additions and 0 deletions

View file

@ -7,5 +7,6 @@ zephyr_library_sources_ifdef(CONFIG_TIMER_TMR_CMSDK_APB timer_tmr_cmsdk_apb.c)
zephyr_library_sources_ifdef(CONFIG_COUNTER_DTMR_CMSDK_APB counter_dtmr_cmsdk_apb.c)
zephyr_library_sources_ifdef(CONFIG_TIMER_DTMR_CMSDK_APB timer_dtmr_cmsdk_apb.c)
zephyr_library_sources_ifdef(CONFIG_COUNTER_NRF_TIMER counter_nrfx_timer.c)
zephyr_library_sources_ifdef(CONFIG_COUNTER_NRF_RTC counter_nrfx_rtc.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE counter_handlers.c)

View file

@ -0,0 +1,280 @@
/*
* Copyright (c) 2018, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <counter.h>
#include <clock_control.h>
#include <drivers/clock_control/nrf5_clock_control.h>
#include <nrfx_rtc.h>
#define LOG_LEVEL CONFIG_COUNTER_LOG_LEVEL
#define LOG_MODULE_NAME counter_rtc
#include <logging/log.h>
LOG_MODULE_REGISTER();
#define RTC_CLOCK 32768
#define COUNTER_MAX_WRAP RTC_COUNTER_COUNTER_Msk
#define CC_TO_ID(cc) ((cc) - 1)
#define ID_TO_CC(id) ((id) + 1)
#define WRAP_CH 0
#define COUNTER_WRAP_INT NRFX_RTC_INT_COMPARE0
struct counter_nrfx_data {
counter_wrap_callback_t wrap_cb;
void *wrap_user_data;
u32_t wrap;
};
struct counter_nrfx_config {
struct counter_config_info info;
const struct counter_alarm_cfg **alarm_cfgs;
nrfx_rtc_t rtc;
LOG_INSTANCE_PTR_DECLARE(log);
};
static inline struct counter_nrfx_data *get_dev_data(struct device *dev)
{
return dev->driver_data;
}
static inline const struct counter_nrfx_config *get_nrfx_config(
struct device *dev)
{
return CONTAINER_OF(dev->config->config_info,
struct counter_nrfx_config, info);
}
static int counter_nrfx_start(struct device *dev)
{
nrfx_rtc_enable(&get_nrfx_config(dev)->rtc);
return 0;
}
static int counter_nrfx_stop(struct device *dev)
{
nrfx_rtc_disable(&get_nrfx_config(dev)->rtc);
return 0;
}
static u32_t counter_nrfx_read(struct device *dev)
{
return nrfx_rtc_counter_get(&get_nrfx_config(dev)->rtc);
}
static int counter_nrfx_set_alarm(struct device *dev,
const struct counter_alarm_cfg *alarm_cfg)
{
const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev);
const nrfx_rtc_t *rtc = &nrfx_config->rtc;
u32_t cc_val;
if (alarm_cfg->ticks > get_dev_data(dev)->wrap) {
return -EINVAL;
}
if (nrfx_config->alarm_cfgs[alarm_cfg->channel_id]) {
return -EBUSY;
}
cc_val = alarm_cfg->ticks + (alarm_cfg->absolute ?
0 : nrfx_rtc_counter_get(rtc));
cc_val = (cc_val > get_dev_data(dev)->wrap) ?
(cc_val - get_dev_data(dev)->wrap) : cc_val;
nrfx_config->alarm_cfgs[alarm_cfg->channel_id] = alarm_cfg;
nrfx_rtc_cc_set(rtc, ID_TO_CC(alarm_cfg->channel_id), cc_val, true);
return 0;
}
static void _disable(struct device *dev, u8_t id)
{
const struct counter_nrfx_config *config = get_nrfx_config(dev);
nrfx_rtc_cc_disable(&config->rtc, ID_TO_CC(id));
config->alarm_cfgs[id] = NULL;
}
static int counter_nrfx_disable_alarm(struct device *dev,
const struct counter_alarm_cfg *alarm_cfg)
{
_disable(dev, alarm_cfg->channel_id);
return 0;
}
static int counter_nrfx_set_wrap(struct device *dev, u32_t ticks,
counter_wrap_callback_t callback,
void *user_data)
{
const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev);
const nrfx_rtc_t *rtc = &nrfx_config->rtc;
struct counter_nrfx_data *dev_data = get_dev_data(dev);
for (int i = 0; i < counter_get_num_of_channels(dev); i++) {
/* Overflow can be changed only when all alarms are
* disables.
*/
if (nrfx_config->alarm_cfgs[i]) {
return -EBUSY;
}
}
nrfx_rtc_cc_disable(rtc, WRAP_CH);
nrfx_rtc_counter_clear(rtc);
dev_data->wrap_cb = callback;
dev_data->wrap_user_data = user_data;
dev_data->wrap = ticks;
nrfx_rtc_cc_set(rtc, WRAP_CH, ticks, callback ? true : false);
return 0;
}
static u32_t counter_nrfx_get_pending_int(struct device *dev)
{
return 0;
}
static void alarm_event_handler(struct device *dev, u32_t id)
{
const struct counter_nrfx_config *config = get_nrfx_config(dev);
const struct counter_alarm_cfg *alarm_cfg = config->alarm_cfgs[id];
u32_t cc_val;
cc_val = nrf_rtc_cc_get(config->rtc.p_reg, ID_TO_CC(id));
_disable(dev, id);
alarm_cfg->handler(dev, alarm_cfg, cc_val);
}
static void event_handler(nrfx_rtc_int_type_t int_type, void *p_context)
{
struct device *dev = p_context;
struct counter_nrfx_data *data = get_dev_data(dev);
if (int_type == COUNTER_WRAP_INT) {
/* Manually reset counter when wrap is different than max wrap*/
if (data->wrap != COUNTER_MAX_WRAP) {
nrfx_rtc_counter_clear(&get_nrfx_config(dev)->rtc);
nrfx_rtc_cc_set(&get_nrfx_config(dev)->rtc,
WRAP_CH, data->wrap, true);
}
if (data->wrap_cb) {
data->wrap_cb(dev, data->wrap_user_data);
}
} else if (int_type > COUNTER_WRAP_INT) {
alarm_event_handler(dev, CC_TO_ID(int_type));
}
}
static int init_rtc(struct device *dev,
const nrfx_rtc_config_t *config,
nrfx_rtc_handler_t handler)
{
struct device *clock;
const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev);
const nrfx_rtc_t *rtc = &nrfx_config->rtc;
clock = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_K32SRC_DRV_NAME);
if (!clock) {
return -ENODEV;
}
clock_control_on(clock, (void *)CLOCK_CONTROL_NRF5_K32SRC);
nrfx_err_t result = nrfx_rtc_init(rtc, config, handler);
if (result != NRFX_SUCCESS) {
LOG_INST_ERR(nrfx_config->log, "Failed to initialize device.");
return -EBUSY;
}
get_dev_data(dev)->wrap = COUNTER_MAX_WRAP;
LOG_INST_DBG(nrfx_config->log, "Initialized");
return 0;
}
static u32_t counter_nrfx_get_wrap(struct device *dev)
{
return get_dev_data(dev)->wrap;
}
static u32_t counter_nrfx_get_max_relative_alarm(struct device *dev)
{
/* Maybe decreased. */
return get_dev_data(dev)->wrap;
}
static const struct counter_driver_api counter_nrfx_driver_api = {
.start = counter_nrfx_start,
.stop = counter_nrfx_stop,
.read = counter_nrfx_read,
.set_alarm = counter_nrfx_set_alarm,
.disable_alarm = counter_nrfx_disable_alarm,
.set_wrap = counter_nrfx_set_wrap,
.get_pending_int = counter_nrfx_get_pending_int,
.get_wrap = counter_nrfx_get_wrap,
.get_max_relative_alarm = counter_nrfx_get_max_relative_alarm,
};
#define COUNTER_NRFX_RTC_DEVICE(idx) \
DEVICE_DECLARE(rtc_##idx); \
static void rtc_##idx##_handler(nrfx_rtc_int_type_t int_type) \
{ \
event_handler(int_type, DEVICE_GET(rtc_##idx)); \
} \
static int counter_##idx##_init(struct device *dev) \
{ \
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_RTC##idx), \
CONFIG_COUNTER_RTC##idx##_IRQ_PRI, \
nrfx_isr, nrfx_rtc_##idx##_irq_handler, 0); \
const nrfx_rtc_config_t config = { \
.prescaler = CONFIG_COUNTER_RTC##idx##_PRESCALER, \
}; \
return init_rtc(dev, &config, rtc_##idx##_handler); \
} \
static struct counter_nrfx_data counter_##idx##_data; \
static const struct counter_alarm_cfg \
*counter##idx##_alarm_cfgs[CC_TO_ID(RTC##idx##_CC_NUM)]; \
LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, CONFIG_COUNTER_LOG_LEVEL); \
static const struct counter_nrfx_config nrfx_counter_##idx##_config = {\
.info = { \
.max_wrap = COUNTER_MAX_WRAP, \
.freq = RTC_CLOCK / \
(CONFIG_COUNTER_RTC##idx##_PRESCALER + 1), \
.count_up = true, \
.channels = CC_TO_ID(RTC##idx##_CC_NUM) \
}, \
.alarm_cfgs = counter##idx##_alarm_cfgs, \
.rtc = NRFX_RTC_INSTANCE(idx), \
LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \
}; \
DEVICE_AND_API_INIT(rtc_##idx, CONFIG_COUNTER_RTC##idx##_NAME, \
counter_##idx##_init, \
&counter_##idx##_data, \
&nrfx_counter_##idx##_config.info, \
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&counter_nrfx_driver_api)
#ifdef CONFIG_COUNTER_RTC0
COUNTER_NRFX_RTC_DEVICE(0);
#endif
#ifdef CONFIG_COUNTER_RTC1
COUNTER_NRFX_RTC_DEVICE(1);
#endif
#ifdef CONFIG_COUNTER_RTC2
COUNTER_NRFX_RTC_DEVICE(2);
#endif

View file

@ -113,6 +113,7 @@ config NRF_RTC_TIMER
default y
depends on CLOCK_CONTROL_NRF
select TICKLESS_CAPABLE
select COUNTER_RTC1
help
This module implements a kernel device driver for the nRF Real Time
Counter NRF_RTC1 and provides the standard "system clock driver"

View file

@ -41,6 +41,18 @@ config NRFX_RTC
config NRFX_SAADC
bool
config NRFX_RTC
bool
config NRFX_RTC0
bool
config NRFX_RTC1
bool
config NRFX_RTC2
bool
config NRFX_SPI
bool

View file

@ -781,6 +781,18 @@
// <e> NRFX_RTC_ENABLED - nrfx_rtc - RTC peripheral driver
//==========================================================
#ifdef CONFIG_NRFX_RTC
#define NRFX_RTC_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC0
#define NRFX_RTC0_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC1
#define NRFX_RTC1_ENABLED 1
#endif
#ifndef NRFX_RTC_ENABLED
#define NRFX_RTC_ENABLED 0
#endif

View file

@ -1466,6 +1466,22 @@
// <e> NRFX_RTC_ENABLED - nrfx_rtc - RTC peripheral driver
//==========================================================
#ifdef CONFIG_NRFX_RTC
#define NRFX_RTC_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC0
#define NRFX_RTC0_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC1
#define NRFX_RTC1_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC2
#define NRFX_RTC2_ENABLED 1
#endif
#ifndef NRFX_RTC_ENABLED
#define NRFX_RTC_ENABLED 0
#endif

View file

@ -1573,6 +1573,22 @@
// <e> NRFX_RTC_ENABLED - nrfx_rtc - RTC peripheral driver
//==========================================================
#ifdef CONFIG_NRFX_RTC
#define NRFX_RTC_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC0
#define NRFX_RTC0_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC1
#define NRFX_RTC1_ENABLED 1
#endif
#ifdef CONFIG_NRFX_RTC2
#define NRFX_RTC2_ENABLED 1
#endif
#ifndef NRFX_RTC_ENABLED
#define NRFX_RTC_ENABLED 0
#endif