Add C5471 watchdog driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@66 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
a84ca3469b
commit
7526641e4e
@ -36,4 +36,5 @@
|
|||||||
|
|
||||||
* Add dirent.h, opendir(), readdir(), closedir(), etc.
|
* Add dirent.h, opendir(), readdir(), closedir(), etc.
|
||||||
* Added 'ls' command to nsh
|
* Added 'ls' command to nsh
|
||||||
|
* Added C5471 watchdog driver
|
||||||
|
|
||||||
|
63
arch/c5471/include/watchdog.h
Normal file
63
arch/c5471/include/watchdog.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/************************************************************
|
||||||
|
* watchdog.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 Gregory Nutt 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_WATCHDOG_H
|
||||||
|
#define __ARCH_WATCHDOG_H
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Included Files
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Definitions
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
/* IOCTL commands supported by the C5471 watchdog driver */
|
||||||
|
|
||||||
|
#define WDIOC_KEEPALIVE 0x5701 /* Restart the watchdog timer */
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Private Data
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Private Functions
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Public Functions
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
#endif /* __ARCH_WATCHDOG_H */
|
@ -51,7 +51,7 @@ CSRCS = up_initialize.c up_initialstate.c up_idle.c up_doirq.c \
|
|||||||
up_exit.c up_assert.c up_blocktask.c up_unblocktask.c \
|
up_exit.c up_assert.c up_blocktask.c up_unblocktask.c \
|
||||||
up_releasepending.c up_reprioritizertr.c up_copystate.c \
|
up_releasepending.c up_reprioritizertr.c up_copystate.c \
|
||||||
up_schedulesigaction.c up_sigdeliver.c up_serial.c \
|
up_schedulesigaction.c up_sigdeliver.c up_serial.c \
|
||||||
up_delay.c up_allocateheap.c up_leds.c
|
up_delay.c up_allocateheap.c up_leds.c up_watchdog.c
|
||||||
COBJS = $(CSRCS:.c=.o)
|
COBJS = $(CSRCS:.c=.o)
|
||||||
|
|
||||||
SRCS = $(ASRCS) $(CSRCS)
|
SRCS = $(ASRCS) $(CSRCS)
|
||||||
|
@ -142,6 +142,10 @@ extern void up_vectorfiq(void);
|
|||||||
extern void up_earlyserialinit(void);
|
extern void up_earlyserialinit(void);
|
||||||
extern void up_serialinit(void);
|
extern void up_serialinit(void);
|
||||||
|
|
||||||
|
/* Defined in up_watchdog.c */
|
||||||
|
|
||||||
|
extern void up_wdtinit(void);
|
||||||
|
|
||||||
/* Defined in up_timerisr.c */
|
/* Defined in up_timerisr.c */
|
||||||
|
|
||||||
extern void up_timerinit(void);
|
extern void up_timerinit(void);
|
||||||
|
392
arch/c5471/src/up_watchdog.c
Normal file
392
arch/c5471/src/up_watchdog.c
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
* up_watchdog.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 Gregory Nutt 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 <nuttx/config.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <nuttx/fs.h>
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
#include <arch/watchdog.h>
|
||||||
|
#include "c5471.h"
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Definitions
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#undef CONFIG_SOFTWARE_TEST
|
||||||
|
#undef CONFIG_SOFTWARE_REBOOT
|
||||||
|
#undef CONFIG_WATCHDOG_STRICT
|
||||||
|
|
||||||
|
#define MAX_WDT_USEC 353200
|
||||||
|
#define MAX_PRESCALER 256
|
||||||
|
#define C5471_TIMER_STOP 0
|
||||||
|
|
||||||
|
#define C5471_TIMER_PRESCALER 0x07 /* Bits 0-2: Prescale value */
|
||||||
|
#define C5471_TIMER_STARTBIT (1 << 3) /* Bit 3: Start timer bit */
|
||||||
|
#define C5471_TIMER_AUTORELOAD (1 << 4) /* Bit 4: Auto-reload timer */
|
||||||
|
#define C5471_TIMER_LOADTIM (0xffff << 5) /* Bits 20-5: Load timer value */
|
||||||
|
#define C5471_TIMER_MODE (1 << 21) /* Bit 21: Timer mode */
|
||||||
|
#define C5471_DISABLE_VALUE1 (0xf5 << 22) /* Bits 29-22: WD disable */
|
||||||
|
#define C5471_DISABLE_VALUE2 (0xa0 << 22)
|
||||||
|
|
||||||
|
#define CLOCK_KHZ 47500
|
||||||
|
#define CLOCK_MHZx2 95
|
||||||
|
|
||||||
|
/* Macros to manage access to to watchdog timer macros */
|
||||||
|
|
||||||
|
#define c5471_wdt_cntl (*(volatile uint32*)C5471_TIMER0_CTRL)
|
||||||
|
#define c5471_wdt_count (*(volatile uint32*)C5471_TIMER0_CNT)
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Private Types
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/* Local implementation of timer interface */
|
||||||
|
|
||||||
|
static inline unsigned int wdt_prescaletoptv(unsigned int prescale);
|
||||||
|
|
||||||
|
static int wdt_setusec(uint32 usec);
|
||||||
|
static int wdt_interrupt(int irq, void *context);
|
||||||
|
|
||||||
|
static int wdt_open(struct file *filep);
|
||||||
|
static int wdt_close(struct file *filep);
|
||||||
|
static ssize_t wdt_read(struct file *filep, char *buffer, size_t buflen);
|
||||||
|
static ssize_t wdt_write(struct file *filep, const char *buffer, size_t buflen);
|
||||||
|
static int wdt_ioctl(struct file *filep, int cmd, uint32 arg);
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Private Data
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static boolean g_wdtopen;
|
||||||
|
|
||||||
|
struct file_operations g_wdtops =
|
||||||
|
{
|
||||||
|
.open = wdt_open,
|
||||||
|
.close = wdt_close,
|
||||||
|
.read = wdt_read,
|
||||||
|
.write = wdt_write,
|
||||||
|
.ioctl = wdt_ioctl,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_prescaletoptv
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static inline unsigned int wdt_prescaletoptv(unsigned int prescale)
|
||||||
|
{
|
||||||
|
unsigned int ptv = 0;
|
||||||
|
|
||||||
|
if (prescale > 255)
|
||||||
|
{
|
||||||
|
ptv = 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int value = prescale >> 1;
|
||||||
|
|
||||||
|
/* 0: 0-2
|
||||||
|
* 1: 3-4
|
||||||
|
* 2: 5-8
|
||||||
|
* 3: 9-16
|
||||||
|
* 4: 17-32
|
||||||
|
* 5: 33-64
|
||||||
|
* 6: 65-128
|
||||||
|
* 7: 129-
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (value > 1)
|
||||||
|
{
|
||||||
|
value >>= 1;
|
||||||
|
ptv++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("prescale=%d -> ptv=%d\n", prescale, ptv);
|
||||||
|
return ptv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_setusec
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static int wdt_setusec(uint32 usec)
|
||||||
|
{
|
||||||
|
/* prescaler: clock / prescaler = #clock ticks per counter in ptv
|
||||||
|
* divisor: #counts until the interrupt comes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32 prescaler = MAX_PRESCALER;
|
||||||
|
uint32 divisor = 1;
|
||||||
|
uint32 mode;
|
||||||
|
|
||||||
|
dbg("usec=%d\n", usec);
|
||||||
|
|
||||||
|
/* Calculate a value of prescaler and divisor that will be able
|
||||||
|
* to count to the usec. It may not be exact or the best
|
||||||
|
* possible set, but it's a quick and simple algorithm.
|
||||||
|
*
|
||||||
|
* divisor max = 0x10000
|
||||||
|
* prescaler max = MAX_PRESCALER
|
||||||
|
*/
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
divisor = (CLOCK_MHZx2 * usec) / (prescaler * 2);
|
||||||
|
dbg("divisor=0x%x prescaler=0x%x\n", divisor, prescaler);
|
||||||
|
|
||||||
|
if (divisor >= 0x10000)
|
||||||
|
{
|
||||||
|
if (prescaler == MAX_PRESCALER)
|
||||||
|
{
|
||||||
|
/* This is the max possible ~2.5 seconds. */
|
||||||
|
|
||||||
|
dbg("prescaler=0x%x too big!\n", prescaler);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
prescaler <<= 1;
|
||||||
|
if (prescaler > MAX_PRESCALER)
|
||||||
|
{
|
||||||
|
prescaler = MAX_PRESCALER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (divisor >= 0x10000);
|
||||||
|
|
||||||
|
dbg("prescaler=0x%x divisor=0x%x\n", prescaler, divisor);
|
||||||
|
|
||||||
|
mode = wdt_prescaletoptv(prescaler);
|
||||||
|
mode &= ~C5471_TIMER_AUTORELOAD; /* One shot mode. */
|
||||||
|
mode |= divisor << 5;
|
||||||
|
dbg("mode=0x%x\n", mode);
|
||||||
|
|
||||||
|
c5471_wdt_cntl = mode;
|
||||||
|
|
||||||
|
/* Now start the watchdog */
|
||||||
|
|
||||||
|
c5471_wdt_cntl |= C5471_TIMER_STARTBIT;
|
||||||
|
dbg("cntl_timer=0x%x\n", c5471_wdt_cntl);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_interrupt
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static int wdt_interrupt(int irq, void *context)
|
||||||
|
{
|
||||||
|
dbg("expired\n");
|
||||||
|
|
||||||
|
#if defined(CONFIG_SOFTWARE_REBOOT)
|
||||||
|
# if defined(CONFIG_SOFTWARE_TEST)
|
||||||
|
dbg(" Test only\n");
|
||||||
|
# else
|
||||||
|
dbg(" Re-booting\n");
|
||||||
|
# warning "Add logic to reset CPU here"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
dbg(" No reboot\n");
|
||||||
|
#endif
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_read
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t wdt_read(struct file *filep, char *buffer, size_t buflen)
|
||||||
|
{
|
||||||
|
/* We are going to return "NNNNNNNN NNNNNNNN." The followig logic will
|
||||||
|
* not work if the user provides a buffer smaller than 18 bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dbg("buflen=%d\n", buflen);
|
||||||
|
if (buflen >= 18)
|
||||||
|
{
|
||||||
|
sprintf(buffer, "#08x %08x\n", c5471_wdt_cntl, c5471_wdt_count);
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_write
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t wdt_write(struct file *filep, const char *buffer, size_t buflen)
|
||||||
|
{
|
||||||
|
dbg("buflen=%d\n", buflen);
|
||||||
|
if (buflen)
|
||||||
|
{
|
||||||
|
/* Reset the timer to the maximum delay */
|
||||||
|
|
||||||
|
wdt_setusec(MAX_WDT_USEC);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_ioctl
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static int wdt_ioctl(struct file *filep, int cmd, uint32 arg)
|
||||||
|
{
|
||||||
|
dbg("ioctl Call: cmd=0x%x arg=0x%x", cmd, arg);
|
||||||
|
|
||||||
|
/* Process the the IOCTL command (see arch/watchdog.h) */
|
||||||
|
|
||||||
|
switch(cmd)
|
||||||
|
{
|
||||||
|
case WDIOC_KEEPALIVE:
|
||||||
|
wdt_setusec(MAX_WDT_USEC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*get_errno_ptr() = ENOTTY;
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_open
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static int wdt_open(struct file *filep)
|
||||||
|
{
|
||||||
|
dbg("");
|
||||||
|
|
||||||
|
if (g_wdtopen)
|
||||||
|
{
|
||||||
|
*get_errno_ptr() = EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This will automatically load the timer with its max
|
||||||
|
* count and start it running.
|
||||||
|
*/
|
||||||
|
|
||||||
|
c5471_wdt_cntl = C5471_DISABLE_VALUE1;
|
||||||
|
c5471_wdt_cntl = C5471_DISABLE_VALUE2;
|
||||||
|
|
||||||
|
g_wdtopen = TRUE;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: wdt_close
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
static int wdt_close(struct file *filep)
|
||||||
|
{
|
||||||
|
dbg("");
|
||||||
|
|
||||||
|
/* The task controlling the watchdog has terminated. Take the timer
|
||||||
|
* the
|
||||||
|
* watchdog in interrupt mode -- we are going to reset unless the
|
||||||
|
* reopened again soon.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_WATCHDOG_STRICT
|
||||||
|
c5471_wdt_cntl = C5471_TIMER_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_wdtopen = FALSE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Name: up_wdtinit
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
int up_wdtinit(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dbg("C547x Watchdog Driver\n");
|
||||||
|
|
||||||
|
/* Register as /dev/wdt */
|
||||||
|
|
||||||
|
ret = register_inode("/dev/wdt", &g_wdtops, 0666, NULL);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register for an interrupt level callback through wdt_interrupt */
|
||||||
|
|
||||||
|
dbg("Attach to IRQ=%d\n", C5471_IRQ_WATCHDOG);
|
||||||
|
|
||||||
|
/* Make sure that the timer is stopped */
|
||||||
|
|
||||||
|
c5471_wdt_cntl = C5471_TIMER_STOP;
|
||||||
|
|
||||||
|
/* Request the interrupt. */
|
||||||
|
|
||||||
|
ret = irq_attach(C5471_IRQ_WATCHDOG, wdt_interrupt);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
unregister_inode("/dev/wdt");
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user