diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index 8cb93b4594..c2657bbd8b 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -217,6 +217,11 @@ config IMXRT_LCD default n depends on IMXRT_HAVE_LCD +config IMXRT_WDOG + bool "Watchdog 1" + default n + depends on WATCHDOG + menu "FlexIO Peripherals" config IMXRT_FLEXIO1 diff --git a/arch/arm/src/imxrt/imxrt_wdog.c b/arch/arm/src/imxrt/imxrt_wdog.c index a3dbb1b772..9302afcf81 100644 --- a/arch/arm/src/imxrt/imxrt_wdog.c +++ b/arch/arm/src/imxrt/imxrt_wdog.c @@ -40,28 +40,346 @@ #include #include -#include +#include + +#include #include +#include + +#include #include "arm_arch.h" - #include "hardware/imxrt_wdog.h" -#include "imxrt_config.h" +#include "imxrt_wdog.h" + #include /* Include last: has dependencies */ +#if defined(CONFIG_WATCHDOG) && defined(CONFIG_IMXRT_WDOG) + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ************************************************************/ + +/* Select the path to the registered watchdog timer device */ + +#ifdef CONFIG_WATCHDOG_DEVPATH +#define DEVPATH CONFIG_WATCHDOG_DEVPATH +#else +#define DEVPATH "/dev/watchdog0" +#endif + +/* Time out range is from 0 to 128 seconds in 0.5s intervals */ + +#define WDOG_MIN (500) +#define WDOG_MAX (128000) + +#define WDOG_KEEP_ALIVE_KEY1 (0x5555u) +#define WDOG_KEEP_ALIVE_KEY2 (0xaaaau) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imxrt_wdog_lower +{ + FAR const struct watchdog_ops_s *ops; /* Lower half operations */ + uint32_t timeout; + uint32_t enabled; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Timeout to register field helper */ + +uint32_t imxrt_wdog_ms_to_reg(uint32_t timeout); + +/* Lower half driver methods */ + +static int imxrt_wdog_start(FAR struct watchdog_lowerhalf_s *lower); +static int imxrt_wdog_stop(FAR struct watchdog_lowerhalf_s *lower); +static int imxrt_wdog_keepalive(FAR struct watchdog_lowerhalf_s *lower); +static int imxrt_wdog_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status); +static int imxrt_wdog_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout); /**************************************************************************** * Private Data ****************************************************************************/ +/* "Lower half" driver ops */ + +static const struct watchdog_ops_s g_wdgops = +{ + .start = imxrt_wdog_start, + .stop = imxrt_wdog_stop, + .keepalive = imxrt_wdog_keepalive, + .getstatus = imxrt_wdog_getstatus, + .settimeout = imxrt_wdog_settimeout, + .capture = NULL, + .ioctl = NULL, +}; + +/* "Lower half" driver state */ + +static struct imxrt_wdog_lower g_wdgdev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_wdog_ms_to_reg + * + * Description: + * Start the watchdog timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * lower-half driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +uint32_t imxrt_wdog_ms_to_reg(uint32_t ms) +{ + uint32_t reg = ms / 500; /* This gives the value needed for + * ms rounded up to the nearest 500ms of timeout + */ + + if (reg != 0 && ms % 500 == 0) + { + /* If the number is divisible by 500ms we subtract 1. + * Else we will set the timeout to the smallest achievable timeout + * that is greater than the requested value. + */ + + reg--; + } + + return reg; +} + +/**************************************************************************** + * Name: imxrt_wdog + * + * Description: + * Start the watchdog timer, setting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * lower-half driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int imxrt_wdog_start(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower; + uint16_t regval; + + if (priv->enabled == false) + { + priv->enabled = true; + + regval = getreg16(IMXRT_WDOG1_WCR); + regval |= WDOG_WCR_WT(imxrt_wdog_ms_to_reg(priv->timeout)); + putreg16(regval, IMXRT_WDOG1_WCR); + + /* Now that the timeout field is properly set, start the watchdog. */ + + regval |= WDOG_WCR_WDE; + putreg16(regval, IMXRT_WDOG1_WCR); + } + + return OK; +} + +/**************************************************************************** + * Name: imxrt_wdog_stop + * + * Description: + * Exists since it is a required function for the watchdog lower-half + * driver. On the IMXRT you cannot disable the watchdog once it is started. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * lower-half driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int imxrt_wdog_stop(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower; + + if (priv->enabled) + { + /* We cannot disable the watchdog once it is enabled. */ + + wderr("ERROR: Cannot stop Wdog once started\n"); + return -ENOSYS; + } + + return OK; +} + +/**************************************************************************** + * Name: imxrt_wdog_keepalive + * + * Description: + * Reset the watchdog timer to the current timeout value, prevent any + * imminent watchdog timeouts. This is sometimes referred as "pinging" + * the watchdog timer or "petting the dog". + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * lower-half driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int imxrt_wdog_keepalive(FAR struct watchdog_lowerhalf_s *lower) +{ + irqstate_t flags = spin_lock_irqsave(); + + putreg16(WDOG_KEEP_ALIVE_KEY1, IMXRT_WDOG1_WSR); + putreg16(WDOG_KEEP_ALIVE_KEY2, IMXRT_WDOG1_WSR); + + spin_unlock_irqrestore(flags); + + return OK; +} + +/**************************************************************************** + * Name: imxrt_wdog_getstatus + * + * Description: + * Get the current watchdog timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * lower-half driver state structure. + * status - The location to return the watchdog status information. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int imxrt_wdog_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status) +{ + FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower; + + status->flags = WDFLAGS_RESET; + + if (priv->enabled) + { + status->flags |= WDFLAGS_ACTIVE; + } + + status->timeout = priv->timeout; + status->timeleft = 0; /* not supported for WDOG1 */ + + return OK; +} + +/**************************************************************************** + * Name: imxrt_wdog_settimeout + * + * Description: + * Set a new timeout value (and reset the watchdog timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * timeout - The new timeout value in milliseconds. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int imxrt_wdog_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout) +{ + uint32_t regval; + FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower; + + if (timeout < WDOG_MIN || timeout > WDOG_MAX) + { + wderr("ERROR: Cannot represent timeout=%d. Range=[%d, %d]\n", + timeout, WDOG_MIN, WDOG_MAX); + return -ERANGE; + } + + priv->timeout = timeout; + + irqstate_t flags = spin_lock_irqsave(); + + /* write timer value to WCR WT register */ + + regval = getreg16(IMXRT_WDOG1_WCR); + regval &= ~WDOG_WCR_WT_MASK; /* clear previous count value */ + regval |= WDOG_WCR_WT(priv->timeout); + putreg16(regval, IMXRT_WDOG1_WCR); + + /* reload the Wdog counter by petting it */ + + putreg16(WDOG_KEEP_ALIVE_KEY1, IMXRT_WDOG1_WSR); + putreg16(WDOG_KEEP_ALIVE_KEY2, IMXRT_WDOG1_WSR); + + spin_unlock_irqrestore(flags); + + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: imxrt_wdog_initialize + * + * Description: + * Initialize the watchdog time. The watchdog timer is initialized and + * registered at devpath. The initial state of the watchdog time is + * disabled. + * + * Input Parameters: + * None + * + * Returned Values: + * None + * + ****************************************************************************/ + +void imxrt_wdog_initialize(void) +{ + FAR struct imxrt_wdog_lower *priv = &g_wdgdev; + + priv->ops = &g_wdgops; + priv->timeout = WDOG_MIN; + + /* Register the watchdog driver at the path */ + + wdinfo("Entry: devpath=%s\n", DEVPATH); + watchdog_register(DEVPATH, (FAR struct watchdog_lowerhalf_s *)priv); +} + +#endif /* CONFIG_WATCHDOG && CONFIG_IMXRT_WDOG */ + /**************************************************************************** * Name: imxrt_wdog_disable * @@ -84,15 +402,14 @@ void imxrt_wdog_disable_all(void) reg = getreg16(IMXRT_WDOG2_WCR); if (reg & WDOG_WCR_WDE) - { - reg &= ~WDOG_WCR_WDE; - putreg16(reg, IMXRT_WDOG2_WCR); - } + { + reg &= ~WDOG_WCR_WDE; + putreg16(reg, IMXRT_WDOG2_WCR); + } flags = enter_critical_section(); putreg32(RTWDOG_UPDATE_KEY, IMXRT_RTWDOG_CNT); - putreg32(0xFFFF, IMXRT_RTWDOG_TOVAL); + putreg32(0xffff, IMXRT_RTWDOG_TOVAL); modifyreg32(IMXRT_RTWDOG_CS, RTWDOG_CS_EN, RTWDOG_CS_UPDATE); leave_critical_section(flags); - } diff --git a/arch/arm/src/imxrt/imxrt_wdog.h b/arch/arm/src/imxrt/imxrt_wdog.h index 6db8dad501..8bf2a0c36d 100644 --- a/arch/arm/src/imxrt/imxrt_wdog.h +++ b/arch/arm/src/imxrt/imxrt_wdog.h @@ -59,6 +59,29 @@ * Public Function Prototypes ****************************************************************************/ +#if defined(CONFIG_WATCHDOG) && defined(CONFIG_IMXRT_WDOG) + +/**************************************************************************** + * Name: imxrt_wdog_initialize + * + * Description: + * Initialize the watchdog time. The watchdog timer is initialized and + * registered at devpath. The initial state of the watchdog time is + * disabled. + * + * Input Parameters: + * devpath - The full path to the watchdog. This should be of the form + * /dev/watchdog0 + * + * Returned Values: + * None + * + ****************************************************************************/ + +void imxrt_wdog_initialize(void); + +#endif /* CONFIG_WATCHDOG && CONFIG_IMXRT_WDOG */ + /**************************************************************************** * Name: imxrt_wdog_disable *