Skip to content
Permalink
Browse files

counter: Update counter API in order to provide more flexibility

This commit introduces new top_value setting configuration structure
with flag for controlling resetting of the counter during change of
top value.

Such change allows for #12068 implementation on hardware which
does not provide alarms.

Signed-off-by: Piotr Zięcik <piotr.ziecik@nordicsemi.no>
Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
Signed-off-by: Benjamin Valentin <benjamin.valentin@ml-pa.com>
  • Loading branch information...
pizi-nordic authored and carlescufi committed Mar 21, 2019
1 parent 3c6c8ed commit 69406e0f9c3fcbac52f09bb1e59887accadbe4b9
@@ -90,11 +90,13 @@ static u32_t counter_gecko_read(struct device *dev)
return RTCC_CounterGet();
}

static int counter_gecko_set_top_value(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int counter_gecko_set_top_value(struct device *dev,
const struct counter_top_cfg *cfg)
{
struct counter_gecko_data *const dev_data = DEV_DATA(dev);
u32_t ticks;
u32_t flags;
int err = 0;

#ifdef CONFIG_SOC_GECKO_HAS_ERRATA_RTCC_E201
const struct counter_gecko_config *const dev_cfg = DEV_CFG(dev);
@@ -114,18 +116,31 @@ static int counter_gecko_set_top_value(struct device *dev, u32_t ticks,

RTCC_IntClear(RTCC_IF_CC1);

dev_data->top_callback = callback;
dev_data->top_user_data = user_data;
dev_data->top_callback = cfg->callback;
dev_data->top_user_data = cfg->user_data;
ticks = cfg->ticks;
flags = cfg->flags;

if (!(flags & COUNTER_TOP_CFG_DONT_RESET)) {
RTCC_CounterSet(0);
}

RTCC_CounterSet(0);
RTCC_ChannelCCVSet(1, ticks);

LOG_DBG("set top value: %u", ticks);

if ((flags & COUNTER_TOP_CFG_DONT_RESET) &&
RTCC_CounterGet() > ticks) {
err = -ETIME;
if (flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
RTCC_CounterSet(0);
}
}

/* Enable the compare interrupt */
RTCC_IntEnable(RTCC_IF_CC1);

return 0;
return err;
}

static u32_t counter_gecko_get_top_value(struct device *dev)
@@ -96,24 +96,24 @@ static u32_t imx_epit_read(struct device *dev)
return value;
}

static int imx_epit_set_top_value(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int imx_epit_set_top_value(struct device *dev,
const struct counter_top_cfg *cfg)
{
EPIT_Type *base = get_epit_config(dev)->base;
struct imx_epit_data *driver_data = dev->driver_data;

/* Disable EPIT Output Compare interrupt for consistency */
EPIT_SetIntCmd(base, false);

driver_data->callback = callback;
driver_data->user_data = user_data;
driver_data->callback = cfg->callback;
driver_data->user_data = cfg->user_data;

/* Set both reload and counter values to "ticks" */
EPIT_SetOverwriteCounter(base, true);
EPIT_SetCounterLoadValue(base, ticks);
/* Set reload value and optionally counter to "ticks" */
EPIT_SetOverwriteCounter(base,
!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET));
EPIT_SetCounterLoadValue(base, cfg->ticks);

if (callback != NULL) {
if (cfg->callback != NULL) {
/* (Re)enable EPIT Output Compare interrupt */
EPIT_SetIntCmd(base, true);
}
@@ -197,17 +197,13 @@ static u32_t rtc_stm32_get_top_value(struct device *dev)
}


static int rtc_stm32_set_top_value(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int rtc_stm32_set_top_value(struct device *dev,
const struct counter_top_cfg *cfg)
{
const struct counter_config_info *info = dev->config->config_info;

ARG_UNUSED(dev);
ARG_UNUSED(callback);
ARG_UNUSED(user_data);

if (ticks != info->max_top_value) {
if ((cfg->ticks != info->max_top_value) ||
!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
return -ENOTSUP;
} else {
return 0;
@@ -133,20 +133,27 @@ static int mcux_rtc_cancel_alarm(struct device *dev, u8_t chan_id)
return 0;
}

static int mcux_rtc_set_top_value(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int mcux_rtc_set_top_value(struct device *dev,
const struct counter_top_cfg *cfg)
{
const struct counter_config_info *info = dev->config->config_info;
const struct mcux_rtc_config *config =
CONTAINER_OF(info, struct mcux_rtc_config, info);
struct mcux_rtc_data *data = dev->driver_data;

if (ticks != info->max_top_value) {
LOG_ERR("Wrap can only be set to 0x%x", info->max_top_value);
if (cfg->ticks != info->max_top_value) {
LOG_ERR("Wrap can only be set to 0x%x.", info->max_top_value);
return -ENOTSUP;
}

data->top_callback = callback;
data->top_user_data = user_data;
if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
RTC_StopTimer(config->base);
config->base->TSR = 0;
RTC_StartTimer(config->base);
}

data->top_callback = cfg->callback;
data->top_user_data = cfg->user_data;

return 0;
}
@@ -141,13 +141,13 @@ static int counter_nrfx_cancel_alarm(struct device *dev, u8_t chan_id)
return 0;
}

static int counter_nrfx_set_top_value(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int counter_nrfx_set_top_value(struct device *dev,
const struct counter_top_cfg *cfg)
{
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);
int err = 0;

for (int i = 0; i < counter_get_num_of_channels(dev); i++) {
/* Overflow can be changed only when all alarms are
@@ -159,14 +159,26 @@ static int counter_nrfx_set_top_value(struct device *dev, u32_t ticks,
}

nrfx_rtc_cc_disable(rtc, TOP_CH);
nrfx_rtc_counter_clear(rtc);

dev_data->top_cb = callback;
dev_data->top_user_data = user_data;
dev_data->top = ticks;
nrfx_rtc_cc_set(rtc, TOP_CH, ticks, callback ? true : false);
dev_data->top_cb = cfg->callback;
dev_data->top_user_data = cfg->user_data;
dev_data->top = cfg->ticks;
nrfx_rtc_cc_set(rtc, TOP_CH, cfg->ticks, false);

if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
nrfx_rtc_counter_clear(rtc);
} else if (counter_nrfx_read(dev) >= cfg->ticks) {
err = -ETIME;
if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
nrfx_rtc_counter_clear(rtc);
}
}

return 0;
if (cfg->callback) {
nrfx_rtc_int_enable(rtc, COUNTER_TOP_INT);
}

return err;
}

static u32_t counter_nrfx_get_pending_int(struct device *dev)
@@ -156,13 +156,13 @@ static int counter_nrfx_cancel_alarm(struct device *dev, u8_t chan_id)
}


static int counter_nrfx_set_top_value(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int counter_nrfx_set_top_value(struct device *dev,
const struct counter_top_cfg *cfg)
{
const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev);
const nrfx_timer_t *timer = &nrfx_config->timer;
struct counter_nrfx_data *data = get_dev_data(dev);
int err = 0;

for (int i = 0; i < counter_get_num_of_channels(dev); i++) {
/* Overflow can be changed only when all alarms are
@@ -174,15 +174,27 @@ static int counter_nrfx_set_top_value(struct device *dev, u32_t ticks,
}

nrfx_timer_compare_int_disable(timer, TOP_CH);
nrfx_timer_clear(timer);

data->top_cb = callback;
data->top_user_data = user_data;
data->top_cb = cfg->callback;
data->top_user_data = cfg->user_data;
nrfx_timer_extended_compare(timer, TOP_CH,
ticks, COUNTER_OVERFLOW_SHORT,
callback ? true : false);
cfg->ticks, COUNTER_OVERFLOW_SHORT,
false);

if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
nrfx_timer_clear(timer);
} else if (counter_nrfx_read(dev) >= cfg->ticks) {
err = -ETIME;
if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
nrfx_timer_clear(timer);
}
}

return 0;
if (cfg->callback) {
nrfx_timer_compare_int_enable(timer, TOP_CH);
}

return err;
}

static u32_t counter_nrfx_get_pending_int(struct device *dev)
@@ -39,9 +39,7 @@ static u32_t aon_counter_qmsi_read(struct device *dev)
}

static int aon_counter_qmsi_set_top(struct device *dev,
u32_t ticks,
counter_top_callback_t callback,
void *user_data)
const struct counter_top_cfg *cfg)

{
return -ENODEV;
@@ -113,19 +113,22 @@ static u32_t aon_timer_qmsi_read(struct device *dev)
}

static int aon_timer_qmsi_set_top(struct device *dev,
u32_t ticks,
counter_top_callback_t callback,
void *user_data)
const struct counter_top_cfg *cfg)
{
qm_aonpt_config_t qmsi_cfg;
int result = 0;

user_cb = callback;
/* Counter is always reset when top value is updated. */
if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
return -ENOTSUP;
}

user_cb = cfg->callback;

qmsi_cfg.callback = aonpt_int_callback;
qmsi_cfg.int_en = true;
qmsi_cfg.count = ticks;
qmsi_cfg.callback_data = user_data;
qmsi_cfg.count = cfg->ticks;
qmsi_cfg.callback_data = cfg->user_data;

if (IS_ENABLED(CONFIG_AON_API_REENTRANCY)) {
k_sem_take(RP_GET(dev), K_FOREVER);
@@ -90,17 +90,13 @@ static int rtc_qmsi_cancel_alarm(struct device *dev, u8_t chan_id)
return 0;
}

static int rtc_qmsi_set_top(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int rtc_qmsi_set_top(struct device *dev,
const struct counter_top_cfg *cfg)
{
const struct counter_config_info *info = dev->config->config_info;

ARG_UNUSED(dev);
ARG_UNUSED(callback);
ARG_UNUSED(user_data);

if (ticks != info->max_top_value) {
if ((cfg->ticks != info->max_top_value) ||
!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
return -ENOTSUP;
} else {
return 0;
@@ -226,48 +226,50 @@ static int counter_sam0_tc32_cancel_alarm(struct device *dev, u8_t chan_id)
return 0;
}

static int counter_sam0_tc32_set_top_value(struct device *dev, u32_t ticks,
counter_top_callback_t callback,
void *user_data)
static int counter_sam0_tc32_set_top_value(struct device *dev,
const struct counter_top_cfg *top_cfg)
{
bool reset = true;
struct counter_sam0_tc32_data *data = DEV_DATA(dev);
const struct counter_sam0_tc32_config *const cfg = DEV_CFG(dev);
TcCount32 *tc = cfg->regs;
int err = 0;
int key = irq_lock();

if (data->ch.callback) {
irq_unlock(key);
return -EBUSY;
}

if (callback) {
data->top_cb = callback;
data->top_user_data = user_data;
if (top_cfg->callback) {
data->top_cb = top_cfg->callback;
data->top_user_data = top_cfg->user_data;
tc->INTENSET.reg = TC_INTFLAG_MC0;
} else {
tc->INTENCLR.reg = TC_INTFLAG_MC0;
}

tc->CC[0].reg = ticks;
tc->CC[0].reg = top_cfg->ticks;

if (reset) {
tc->CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
} else {
if (top_cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
/*
* Top trigger is on equality of the rising edge only, so
* manually reset it if the counter has missed the new top.
*/
if (counter_sam0_tc32_read(dev) >= ticks) {
tc->CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
if (counter_sam0_tc32_read(dev) >= top_cfg->ticks) {
err = -ETIME;
if (top_cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
tc->CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
}
}
} else {
tc->CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
}

wait_synchronization(tc);

tc->INTFLAG.reg = TC_INTFLAG_MC0;
irq_unlock(key);
return 0;
return err;
}

static u32_t counter_sam0_tc32_get_pending_int(struct device *dev)

0 comments on commit 69406e0

Please sign in to comment.
You can’t perform that action at this time.