diff --git a/drivers/timers/CMakeLists.txt b/drivers/timers/CMakeLists.txt index bde7acf5144..d77de9b3ca4 100644 --- a/drivers/timers/CMakeLists.txt +++ b/drivers/timers/CMakeLists.txt @@ -30,6 +30,10 @@ if(CONFIG_TIMER) list(APPEND SRCS timer.c) endif() +if(CONFIG_TIMER_WDOG) + list(APPEND SRCS timer_wdog.c) +endif() + if(CONFIG_TIMER_ARCH) list(APPEND SRCS arch_timer.c) endif() diff --git a/drivers/timers/Kconfig b/drivers/timers/Kconfig index e8edd85b291..2c796d10c50 100644 --- a/drivers/timers/Kconfig +++ b/drivers/timers/Kconfig @@ -129,6 +129,12 @@ config TIMER_ARCH ---help--- Implement timer arch API on top of timer driver interface. +config TIMER_WDOG + bool "Timer Implementation by watchdog" + default n + ---help--- + This option allows the timer implementation to be based on the + watchdog (wdog) driver interface. endif # TIMER config ONESHOT diff --git a/drivers/timers/Make.defs b/drivers/timers/Make.defs index 03e8247813e..0cdbf677ab9 100644 --- a/drivers/timers/Make.defs +++ b/drivers/timers/Make.defs @@ -34,6 +34,12 @@ ifeq ($(CONFIG_TIMER),y) TMRVPATH = :timers endif +ifeq ($(CONFIG_TIMER_WDOG),y) + CSRCS += timer_wdog.c + TMRDEPPATH = --dep-path timers + TMRVPATH = :timers +endif + ifeq ($(CONFIG_TIMER_ARCH),y) CSRCS += arch_timer.c TMRDEPPATH = --dep-path timers diff --git a/drivers/timers/timer_wdog.c b/drivers/timers/timer_wdog.c new file mode 100644 index 00000000000..56d5ca03e1b --- /dev/null +++ b/drivers/timers/timer_wdog.c @@ -0,0 +1,303 @@ +/**************************************************************************** + * drivers/timers/timer_wdog.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +struct timer_wdog_dev_s +{ + struct timer_lowerhalf_s lower; /* Lower half operations */ + struct wdog_period_s wdog; /* Software watchdog timer */ + spinlock_t lock; + tccb_t callback; /* used for timer handler */ + FAR void *arg; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void timer_wdog_handler(wdparm_t arg); +static int timer_wdog_start(FAR struct timer_lowerhalf_s *lower); +static int timer_wdog_stop(FAR struct timer_lowerhalf_s *lower); +static void timer_wdog_setcallback(FAR struct timer_lowerhalf_s *lower, + tccb_t callback, FAR void *arg); +static int timer_wdog_tick_getstatus(FAR struct timer_lowerhalf_s *lower, + FAR struct timer_status_s *status); +static int timer_wdog_tick_settimeout(FAR struct timer_lowerhalf_s *lower, + uint32_t timeout); +static int timer_wdog_tick_maxtimeout(FAR struct timer_lowerhalf_s *lower, + FAR uint32_t *maxtimeout); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct timer_ops_s g_timer_wdog_ops = +{ + .start = timer_wdog_start, + .stop = timer_wdog_stop, + .setcallback = timer_wdog_setcallback, + .tick_getstatus = timer_wdog_tick_getstatus, + .tick_settimeout = timer_wdog_tick_settimeout, + .tick_maxtimeout = timer_wdog_tick_maxtimeout, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: timer_wdog_start + * + * Description: + * start the timer + * + ****************************************************************************/ + +static int timer_wdog_start(FAR struct timer_lowerhalf_s *lower) +{ + FAR struct timer_wdog_dev_s *priv = (FAR struct timer_wdog_dev_s *)lower; + + DEBUGASSERT(priv); + + if (priv->callback == NULL) + { + /* Return EINVAL to indicate that the timer was not configured */ + + return -EINVAL; + } + + wd_start_period(&priv->wdog, wd_get_period(&priv->wdog), + wd_get_period(&priv->wdog), + timer_wdog_handler, (wdparm_t)priv); + return 0; +} + +/**************************************************************************** + * Name: timer_wdog_stop + * + * Description: + * stop the timer + * + ****************************************************************************/ + +static int timer_wdog_stop(FAR struct timer_lowerhalf_s *lower) +{ + FAR struct timer_wdog_dev_s *priv = (FAR struct timer_wdog_dev_s *)lower; + irqstate_t flags; + + DEBUGASSERT(priv); + + wd_cancel_period(&priv->wdog); + + flags = spin_lock_irqsave(&priv->lock); + priv->callback = NULL; + priv->arg = NULL; + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/**************************************************************************** + * Name: timer_wdog_setcallback + * + * Description: + * set callback function of the timer + * + ****************************************************************************/ + +static void timer_wdog_setcallback(FAR struct timer_lowerhalf_s *lower, + tccb_t callback, FAR void *arg) +{ + FAR struct timer_wdog_dev_s *priv = (FAR struct timer_wdog_dev_s *)lower; + irqstate_t flags; + + DEBUGASSERT(priv); + + flags = spin_lock_irqsave(&priv->lock); + priv->callback = callback; + priv->arg = arg; + spin_unlock_irqrestore(&priv->lock, flags); +} + +/**************************************************************************** + * Name: timer_wdog_getstatus + * + * Description: + * get status of the timer + * + ****************************************************************************/ + +static int timer_wdog_tick_getstatus(FAR struct timer_lowerhalf_s *lower, + FAR struct timer_status_s *status) +{ + FAR struct timer_wdog_dev_s *priv = (FAR struct timer_wdog_dev_s *)lower; + irqstate_t flags; + + DEBUGASSERT(priv); + + status->flags = 0; + + flags = spin_lock_irqsave(&priv->lock); + if (WDOG_ISACTIVE(&priv->wdog.wdog)) + { + /* TIMER is running */ + + status->flags |= TCFLAGS_ACTIVE; + } + + if (priv->callback != NULL) + { + /* TIMER has a user callback function to be called when + * expiration happens + */ + + status->flags |= TCFLAGS_HANDLER; + } + + status->timeout = wd_get_period(&priv->wdog); + status->timeleft = wd_gettime(&priv->wdog.wdog); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/**************************************************************************** + * Name: timer_wdog_settimeout + * + * Description: + * set timeout of the timer + * + ****************************************************************************/ + +static int timer_wdog_tick_settimeout(FAR struct timer_lowerhalf_s *lower, + uint32_t timeout) +{ + FAR struct timer_wdog_dev_s *priv = (FAR struct timer_wdog_dev_s *)lower; + irqstate_t flags; + + DEBUGASSERT(priv); + + flags = spin_lock_irqsave(&priv->lock); + wd_set_period(&priv->wdog, timeout); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/**************************************************************************** + * Name: timer_wdog_tick_maxtimeout + * + * Description: + * get the max timeout value (tick) of the timer + * + ****************************************************************************/ + +static int timer_wdog_tick_maxtimeout(FAR struct timer_lowerhalf_s *lower, + FAR uint32_t *maxtimeout) +{ + *maxtimeout = 0xffffffff; + return 0; +} + +/**************************************************************************** + * Name: timer_wdog_handler + * + * Description: + * wdog handler of the timer + * + ****************************************************************************/ + +static void timer_wdog_handler(wdparm_t arg) +{ + FAR struct timer_wdog_dev_s *priv = (FAR struct timer_wdog_dev_s *)arg; + + if (priv->callback) + { + uint32_t next_interval_us = wd_get_period(&priv->wdog); + + if (priv->callback(&next_interval_us, priv->arg)) + { + if (next_interval_us) + { + wd_set_period(&priv->wdog, next_interval_us); + } + } + else + { + wd_cancel_period(&priv->wdog); + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: timer_wdog_initialize + * + * Description: + * initialize one timer which is implemented by watchdog + * + ****************************************************************************/ + +int timer_wdog_initialize(int timer_id) +{ + FAR struct timer_wdog_dev_s *dev; + char name[64]; + + dev = kmm_zalloc(sizeof(struct timer_wdog_dev_s)); + if (dev == NULL) + { + tmrerr("zalloc failed for timer id = %d!\n", timer_id); + return -ENOMEM; + } + + dev->lower.ops = &g_timer_wdog_ops; + + spin_lock_init(&dev->lock); + + snprintf(name, sizeof(name), "/dev/timer%d", timer_id); + + if (timer_register(name, &dev->lower) == NULL) + { + return -EEXIST; + } + + return OK; +} diff --git a/include/nuttx/timers/timer_wdog.h b/include/nuttx/timers/timer_wdog.h new file mode 100644 index 00000000000..55267bd544c --- /dev/null +++ b/include/nuttx/timers/timer_wdog.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * include/nuttx/timers/timer_wdog.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_TIMERS_TIMERS_WDOG_H +#define __INCLUDE_NUTTX_TIMERS_TIMERS_WDOG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifdef CONFIG_TIMER_WDOG +int timer_wdog_initialize(int timer_id); +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_TIMERS_TIMERS_WDOG_H */