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.
|
||||
* 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_releasepending.c up_reprioritizertr.c up_copystate.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)
|
||||
|
||||
SRCS = $(ASRCS) $(CSRCS)
|
||||
|
@ -142,6 +142,10 @@ extern void up_vectorfiq(void);
|
||||
extern void up_earlyserialinit(void);
|
||||
extern void up_serialinit(void);
|
||||
|
||||
/* Defined in up_watchdog.c */
|
||||
|
||||
extern void up_wdtinit(void);
|
||||
|
||||
/* Defined in up_timerisr.c */
|
||||
|
||||
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