diff --git a/arch/arm/src/lpc54xx/chip/lpc54_syscon.h b/arch/arm/src/lpc54xx/chip/lpc54_syscon.h index 35112d1750..5f8883bfd0 100644 --- a/arch/arm/src/lpc54xx/chip/lpc54_syscon.h +++ b/arch/arm/src/lpc54xx/chip/lpc54_syscon.h @@ -732,8 +732,46 @@ #define SYSCON_FROCTRL_ /* System oscillator control */ #define SYSCON_SYSOSCCTRL_ + /* Watchdog oscillator control */ -#define SYSCON_WDTOSCCTRL_ + +#define SYSCON_WDTOSCCTRL_DIVSEL_SHIFT (0) /* Bits 0-4: Divider adjust oscillator value */ +#define SYSCON_WDTOSCCTRL_DIVSEL_MASK (0x1f << SYSCON_WDTOSCCTRL_DIVSEL_SHIFT) +# define SYSCON_WDTOSCCTRL_DIVSEL(n) ((uint32_t)(((n) >> 1) - 1) << SYSCON_WDTOSCCTRL_DIVSEL_SHIFT) +#define SYSCON_WDTOSCCTRL_FREQSEL_SHIFT (5) /* Bits 5-9: Frequency select */ +#define SYSCON_WDTOSCCTRL_FREQSEL_MASK (0x1f << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) +# define SYSCON_WDTOSCCTRL_FREQSEL_04pMHZ (1 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 0.4 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_0p75MHZ (2 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 0.6 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_0p9MHZ (3 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 0.75 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_0p9MHZ (4 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 0.9 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p0MHZ (5 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.0 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p2MHZ (6 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.2 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p3MHZ (7 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.3 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p4MHZ (8 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.4 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p5MHZ (9 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.5 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p6MHZ (10 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.6 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p7MHZ (11 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.7 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p8MHZ (12 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.8 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_1p9MHZ (13 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 1.9 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p0MHZ (14 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.0 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p05MHZ (15 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.05 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p1MHZ (16 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.1 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p2MHZ (17 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.2 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p25MHZ (18 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.25 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p3MHZ (19 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.3 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p4MHZ (20 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.4 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p45MHZ (21 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.45 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p5MHZ (22 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.5 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p6MHZ (23 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.6 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p65MHZ (24 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.65 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p7MHZ (25 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.7 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p8MHZ (26 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.8 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p85MHZ (27 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.85 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p9MHZ (28 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.9 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_2p95MHZ (29 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 2.95 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_3p0MHZ (30 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 3.0 MHz */ +# define SYSCON_WDTOSCCTRL_FREQSEL_3p05MHZ (31 << SYSCON_WDTOSCCTRL_FREQSEL_SHIFT) /* 3.05 MHz */ + /* RTC oscillator 32 kHz output control */ #define SYSCON_RTCOSCCTRL_ /* USB PLL control */ diff --git a/arch/arm/src/lpc54xx/chip/lpc54_wwdt.h b/arch/arm/src/lpc54xx/chip/lpc54_wwdt.h index af98cb0352..c292304d30 100644 --- a/arch/arm/src/lpc54xx/chip/lpc54_wwdt.h +++ b/arch/arm/src/lpc54xx/chip/lpc54_wwdt.h @@ -41,6 +41,7 @@ ************************************************************************************/ #include +#include "chip/lpc54_memorymap.h" /************************************************************************************ * Pre-processor Definitions @@ -74,7 +75,7 @@ #define WWDT_MOD_WDTOF (1 << 2) /* Bit 2: Watchdog time-out */ #define WWDT_MOD_WDINT (1 << 3) /* Bit 3: Watchdog interrupt */ #define WWDT_MOD_WDPROTECT (1 << 4) /* Bit 4: Watchdog update mode */ -#define WWDT_MOD_WDPROTECT (1 << 5) /* Bit 5: Watchdog lock */ +#define WWDT_MOD_LOCK (1 << 5) /* Bit 5: Prevent disabling WDT */ /* Bits 6-31: Reserved */ /* Watchdog timer constant register */ diff --git a/arch/arm/src/lpc54xx/lpc54_dma.c b/arch/arm/src/lpc54xx/lpc54_dma.c index b09155afbc..d6d727546a 100644 --- a/arch/arm/src/lpc54xx/lpc54_dma.c +++ b/arch/arm/src/lpc54xx/lpc54_dma.c @@ -67,7 +67,6 @@ struct lpc54_dmach_s { bool inuse; /* True: The channel is in use */ - uint16_t nxfrs; /* Number of bytes to transfers */ dma_callback_t callback; /* DMA completion callback function */ void *arg; /* Argument to pass to the callback function */ }; diff --git a/arch/arm/src/lpc54xx/lpc54_wwdt.c b/arch/arm/src/lpc54xx/lpc54_wwdt.c new file mode 100644 index 0000000000..a3dd6996f4 --- /dev/null +++ b/arch/arm/src/lpc54xx/lpc54_wwdt.c @@ -0,0 +1,681 @@ +/**************************************************************************** + * arch/arm/src/lpc54xx/lpc54_wwdt.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "up_arch.h" +#include "chip/lpc54_wwdt.h" +#include "lpc54_power.h" +#include "lpc54_wdt.h" + +#if defined(CONFIG_WATCHDOG) && defined(CONFIG_LPC54_WWDT) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Clocking *****************************************************************/ + +#define WWDT_FREQ 3000000 /* Watchdog clock is IRC 12MHz, but + * it has fixed divider by 4 */ +#define LPC54_MAX_WWDT_TC 0xFFFFFF /* 24-bit counter max value */ +#define LPC54_MIN_WWDT_TC 0xFF /* 8-bit counter min value */ +#define LPC54_MAX_WWDT_WINDOW 0xFFFFFF /* 24-bit max value */ +#define LPC54_MIN_WWDT_WINDOW 0x100 /* Minimum window value allowed */ +#define WWDT_WARNINT_VALUE 0x3FF /* 10-bit max value */ +#define WWDT_MAXTIMEOUT 5592 /* Max timeout value in miliseconds */ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_LPC54_WWDT_DEFTIMOUT +# define CONFIG_LPC54_WWDT_DEFTIMOUT WWDT_MAXTIMEOUT +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * well-known watchdog_lowerhalf_s structure. + */ + +struct lpc54_lowerhalf_wwdt_s +{ + FAR const struct watchdog_ops_s *ops; /* Lower half operations */ + xcpt_t handler; /* Current watchdog interrupt handler */ + uint32_t timeout; /* The actual timeout value */ + bool started; /* The timer has been started */ + uint32_t reload; /* The 24-bit reload field reset value */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void lpc54_setwindow(uint32_t window); +static void lpc54_setwarning(uint32_t warning); + +/* Interrupt hanlding *******************************************************/ + +static int lpc54_interrupt(int irq, FAR void *context); + +/* "Lower half" driver methods **********************************************/ + +static int lpc54_start(FAR struct watchdog_lowerhalf_s *lower); +static int lpc54_stop(FAR struct watchdog_lowerhalf_s *lower); +static int lpc54_keepalive(FAR struct watchdog_lowerhalf_s *lower); +static int lpc54_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status); +static int lpc54_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout); +static xcpt_t lpc54_capture(FAR struct watchdog_lowerhalf_s *lower, + xcpt_t handler); +static int lpc54_ioctl(FAR struct watchdog_lowerhalf_s *lower, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct watchdog_ops_s g_wdgops = +{ + .start = lpc54_start, + .stop = lpc54_stop, + .keepalive = lpc54_keepalive, + .getstatus = lpc54_getstatus, + .settimeout = lpc54_settimeout, + .capture = lpc54_capture, + .ioctl = lpc54_ioctl, +}; + +/* "Lower half" driver state */ + +static struct lpc54_lowerhalf_wwdt_s g_wdgdev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc54_setwindow + * + * Description: + * The window register determines the highest timeout value allowed when a + * watchdog feed is performed. If a feed valid sequence completes prior to + * timeout value reaching the value in window, a watchdog event will occur. + * + * window resets to the maximum possible timeout value, so windowing is not + * in effect. Values of window below 0x100 will make it impossible to ever + * feed the watchdog successfully + * + ****************************************************************************/ + +static void lpc54_setwindow(uint32_t window) +{ + /* WWDT window minimum value limiting */ + + if (window < 0x100) + { + window = 0x100; + } + + putreg32(window, LPC54_WWDT_WINDOW); +} + +/**************************************************************************** + * Name: lpc54_setwarning + * + * Description: + * The WDWARNINT register determines the watchdog timer counter value that + * will generate a watchdog interrupt. When the watchdog timer counter + * matches the value defined by WDWARNINT, an interrupt will be generated + * after the subsequent WDCLK. A match of the watchdog timer counter to + * WDWARNINT occurs when the bottom 10 bits of the counter have the same + * value as the 10 bits of WARNINT, and the remaining upper bits of the + * counter are all 0. This gives a maximum time of 1,023 watchdog timer + * counts (4,096 watchdog clocks) for the interrupt to occur prior to a + * watchdog event. If WDWARNINT is set to 0, the interrupt will occur at + * the same time as the watchdog event. + * + ****************************************************************************/ + +static void lpc54_setwarning(uint32_t warning) +{ + /* WWDT warning maximum value limiting */ + + if (warning > 0x3FF) + { + warning = 0x3FF; + } + + putreg32(warning, LPC54_WWDT_WARNINT); +} + +/**************************************************************************** + * Name: lpc54_interrupt + * + * Description: + * WWDT warning interrupt + * + * Input Parameters: + * Usual interrupt handler arguments. + * + * Returned Values: + * Always returns OK. + * + ****************************************************************************/ + +static int lpc54_interrupt(int irq, FAR void *context) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = &g_wdgdev; + uint32_t regval; + + /* Check if the watchdog warning interrupt is really pending */ + + regval = getreg32(LPC54_WWDT_MOD); + if ((regval & WWDT_MOD_WDINT) != 0) + { + /* Is there a registered handler? */ + + if (priv->handler) + { + /* Yes... NOTE: This interrupt service routine (ISR) must reload + * the WWDT counter to prevent the reset. Otherwise, we will + * reset upon return. + */ + + priv->handler(irq, context); + } + + /* The watchdog interrupt flag is cleared by writing '1' to the WDINT + * bit in the WDMOD register. + */ + + regval |= WWDT_MOD_WDINT; + putreg32(regval, LPC54_WWDT_MOD); + } + + return OK; +} + +/**************************************************************************** + * Name: lpc54_start + * + * 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. + * + ****************************************************************************/ + +static int lpc54_start(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = + (FAR struct lpc54_lowerhalf_wwdt_s *)lower; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* The watchdog is always disabled after a reset. It is enabled by setting + * the WDEN bit in the WDMOD register, then it cannot be disabled again + * except by a reset. + * + * Watchdog is enabled and will reset the chip + */ + + putreg32(WWDT_MOD_WDEN | WWDT_MOD_WDRESET , LPC54_WWDT_MOD); + + /* Feed the watchdog to enable it */ + + putreg32(0xAA, LPC54_WWDT_FEED); + putreg32(0x55, LPC54_WWDT_FEED); + + priv->started = true; + return OK; +} + +/**************************************************************************** + * Name: lpc54_stop + * + * Description: + * Stop the watchdog timer + * + * 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 lpc54_stop(FAR struct watchdog_lowerhalf_s *lower) +{ + + /* The watchdog is always disabled after a reset. It is enabled by setting + * the WDEN bit in the WDMOD register, then it cannot be disabled again + * except by a reset. + */ + + wdinfo("Entry\n"); + return -ENOSYS; +} + +/**************************************************************************** + * Name: lpc54_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 "feeding the dog". + * + * The application program must write in the FEED register at regular + * intervals during normal operation to prevent an MCU reset. This operation + * must occur only when the counter value is lower than the window register + * value. + * + * 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 lpc54_keepalive(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = + (FAR struct lpc54_lowerhalf_wwdt_s *)lower; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* Feed the watchdog */ + + putreg32(0xAA, LPC54_WWDT_FEED); + putreg32(0x55, LPC54_WWDT_FEED); + + return OK; +} + +/**************************************************************************** + * Name: lpc54_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 lpc54_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = + (FAR struct lpc54_lowerhalf_wwdt_s *)lower; + uint32_t elapsed; + uint32_t reload; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* Return the status bit */ + + status->flags = WDFLAGS_RESET; + if (priv->started) + { + status->flags |= WDFLAGS_ACTIVE; + } + + if (priv->handler) + { + status->flags |= WDFLAGS_CAPTURE; + } + + /* Return the actual timeout is milliseconds */ + + status->timeout = priv->timeout; + + /* Get the time remaining until the watchdog expires (in milliseconds) */ + + + reload = getreg32(LPC54_WWDT_TC); + elapsed = priv->reload - reload; + status->timeleft = (priv->timeout * elapsed) / (priv->reload + 1); + + wdinfo("Status :\n"); + wdinfo(" flags : %08x\n", status->flags); + wdinfo(" timeout : %d\n", status->timeout); + wdinfo(" timeleft : %d\n", status->flags); + return OK; +} + +/**************************************************************************** + * Name: lpc54_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 lpc54_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = + (FAR struct lpc54_lowerhalf_wwdt_s *)lower; + uint32_t reload; + uint32_t regval; + + DEBUGASSERT(priv); + wdinfo("Entry: timeout=%d\n", timeout); + + /* Can this timeout be represented? */ + + if (timeout < 1 || timeout > WWDT_MAXTIMEOUT) + { + wderr("ERROR: Cannot represent timeout=%d > %d\n", + timeout, WWDT_MAXTIMEOUT_MS); + return -ERANGE; + } + + /* Determine timeout value */ + + reload = WWDT_FREQ/1000; + reload = timeout * reload; + + /* Make sure that the final reload value is within range */ + + if (reload > LPC54_MAX_WWDT_TC) + { + reload = LPC54_MAX_WWDT_TC; + } + + /* Save the actual timeout value in milliseconds*/ + + priv->timeout = timeout; + + /* Remember the selected values */ + + priv->reload = reload; + wdinfo("reload=%d timout=%d\n", reload, priv->timeout); + regval = reload; + putreg32(regval, LPC54_WWDT_TC); + + /* Reset the t window value to the maximum value.. essentially disabling + * the lower limit of the watchdog reset time. + */ + + lpc54_setwindow(LPC54_MAX_WWDT_WINDOW); + + /* Set the warning interrupt register value */ + + lpc54_setwarning(WWDT_WARNINT_VALUE); + return OK; +} + +/**************************************************************************** + * Name: lpc54_capture + * + * Description: + * Don't reset on watchdog timer timeout; instead, call this user provider + * timeout handler. NOTE: Providing handler==NULL will restore the reset + * behavior. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * newhandler - The new watchdog expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * + * Returned Values: + * The previous watchdog expiration function pointer or NULL is there was + * no previous function pointer, i.e., if the previous behavior was + * reset-on-expiration (NULL is also returned if an error occurs). + * + ****************************************************************************/ + +static xcpt_t lpc54_capture(FAR struct watchdog_lowerhalf_s *lower, + xcpt_t handler) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = + (FAR struct lpc54_lowerhalf_wwdt_s *)lower; + irqstate_t flags; + xcpt_t oldhandler; + uint16_t regval; + + DEBUGASSERT(priv); + wdinfo("Entry: handler=%p\n", handler); + + /* Get the old handler return value */ + + flags = enter_critical_section(); + oldhandler = priv->handler; + + /* Save the new handler */ + + priv->handler = handler; + + /* Are we attaching or detaching the handler? */ + + regval = getreg32(LPC54_WWDT_MOD); + if (handler) + { + /* Attaching... Enable the watchdog interrupt */ + + regval |= WWDT_MOD_WDINT; + putreg32(regval, LPC54_WWDT_MOD); + + up_enable_irq(LPC54M4_IRQ_WWDT); + } + else + { + /* Detaching... Disable the EWI interrupt */ + + regval &= ~WWDT_MOD_WDINT; + putreg32(regval, LPC54_WWDT_MOD); + + up_disable_irq(LPC54M4_IRQ_WWDT); + } + + leave_critical_section(flags); + return oldhandler; +} + +/**************************************************************************** + * Name: lp54_ioctl + * + * Description: + * Any ioctl commands that are not recognized by the "upper-half" driver + * are forwarded to the lower half driver through this method. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * cmd - The ioctl command value + * arg - The optional argument that accompanies the 'cmd'. The + * interpretation of this argument depends on the particular + * command. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int lpc54_ioctl(FAR struct watchdog_lowerhalf_s *lower, int cmd, + unsigned long arg) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = + (FAR struct lpc54_lowerhalf_wwdt_s *)lower; + int ret = -ENOTTY; + + DEBUGASSERT(priv); + wdinfo("Entry: cmd=%d arg=%ld\n", cmd, arg); + + /* WDIOC_MINTIME: Set the minimum ping time. If two keepalive ioctls + * are received within this time, a reset event will be generated. + * Argument: A 32-bit time value in milliseconds. + */ + + if (cmd == WDIOC_MINTIME) + { + uint32_t mintime = (uint32_t)arg; + + /* The minimum time should be strictly less than the total delay + * which, in turn, will be less than or equal to LPC54_MAX_WWDT_TC + */ + + ret = -EINVAL; + if (mintime < priv->timeout) + { + uint32_t window = mintime*WWDT_FREQ/1000; + DEBUGASSERT(window < priv->reload); + lpc54_setwindow( window ); + ret = OK; + } + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc54_wwdt_initialize + * + * Description: + * Initialize the WWDT watchdog time. The watchdog timer is initialized and + * registers as '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 lpc54_wwdt_initialize(FAR const char *devpath) +{ + FAR struct lpc54_lowerhalf_wwdt_s *priv = &g_wdgdev; + + wdinfo("Entry: devpath=%s\n", devpath); + + /* Initialize the driver state structure. Here we assume: (1) the state + * structure lies in .bss and was zeroed at reset time. (2) This function + * is only called once so it is never necessary to re-zero the structure. + */ + + priv->ops = &g_wdgops; + + /* Turn on and configure the Watchdog oscillator. See the PDEN_WDT_OSC bit + * in the PDRUNCG0 register, and the Watchdog oscillator control register, + * WDTOSCCTRL. + */ + + lpc54_wdtosc_powerup(); +#warning "Mising logic" + + /* Enable the register interface (WWDT bus clock): set the WWDT bit in the + * AHBCLKCTRL0 register. + */ + + lpc54_wwdt_enableclk(); + + /* For waking up from a WWDT interrupt, enable the watchdog interrupt for + * wake-up in the STARTER0 register. + */ + + /* Set watchdog mode register o zero */ + + putreg32(0, LPC54_WWDT_MOD); + + /* Attach our watchdog interrupt handler (But don't enable it yet) */ + + (void)irq_attach(LPC54M4_IRQ_WWDT, lpc54_interrupt); + + /* Select an arbitrary initial timeout value. But don't start the watchdog + * yet. NOTE: If the "Hardware watchdog" feature is enabled through the + * device option bits, the watchdog is automatically enabled at power-on. + */ + + lpc54_settimeout((FAR struct watchdog_lowerhalf_s *)priv, + CONFIG_LPC54_WWDT_DEFTIMOUT); + + /* Register the watchdog driver as /dev/watchdog0 */ + + (void)watchdog_register(devpath, (FAR struct watchdog_lowerhalf_s *)priv); +} + +#endif /* CONFIG_WATCHDOG && CONFIG_LPC54_WWDT */ diff --git a/arch/arm/src/lpc54xx/lpc54_wwdt.h b/arch/arm/src/lpc54xx/lpc54_wwdt.h new file mode 100644 index 0000000000..db0822a48e --- /dev/null +++ b/arch/arm/src/lpc54xx/lpc54_wwdt.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * arch/arm/src/lpc54xx/lpc54_wdt.h + * + * Copyright (C) 2012, 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC54XX_CHIP_LPC54_WDT_H +#define __ARCH_ARM_SRC_LPC54XX_CHIP_LPC54_WDT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "chip/lpc54_wdt.h" + +#ifdef CONFIG_WATCHDOG + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc54_wwdt_initialize + * + * Description: + * Initialize the WWDG watchdog time. The watchdog timer is initializeed and + * registers as '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 + * + ****************************************************************************/ + +#ifdef CONFIG_LPC54_WWDT +void lpc54_wwdt_initialize(FAR const char *devpath); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_WATCHDOG */ +#endif /* __ARCH_ARM_SRC_LPC54XX_CHIP_LPC54_WDT_H */