diff -Nurb linux/arch/mips/au1000/mtx-1/Makefile linux.wd/arch/mips/au1000/mtx-1/Makefile --- linux/arch/mips/au1000/mtx-1/Makefile 2004-11-24 12:11:54.000000000 +0100 +++ linux.wd/arch/mips/au1000/mtx-1/Makefile 2005-03-09 17:58:40.000000000 +0100 @@ -15,6 +15,6 @@ O_TARGET := mtx-1.o -obj-y := init.o board_setup.o irqmap.o +obj-y := init.o board_setup.o irqmap.o mtx-1_watchdog.o include $(TOPDIR)/Rules.make diff -Nurb linux/arch/mips/au1000/mtx-1/mtx-1_watchdog.c linux.wd/arch/mips/au1000/mtx-1/mtx-1_watchdog.c --- linux/arch/mips/au1000/mtx-1/mtx-1_watchdog.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.wd/arch/mips/au1000/mtx-1/mtx-1_watchdog.c 2005-03-09 18:28:06.000000000 +0100 @@ -0,0 +1,216 @@ +/* + * Driver for the MTX-1 Watchdog. + * + * (c) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved. + * http://www.4g-systems.biz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Michael Stickel nor 4G Systems admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2005 4G Systems <info@4g-systems.biz> + * + * Release 0.01. + * + * Author: Michael Stickel michael.stickel@4g-systems.biz + * + * + * The Watchdog is configured to reset the MTX-1 + * if it is not triggered for 100 seconds. + * It should not be triggered more often than 1.6 seconds. + * + * A timer triggers the watchdog every 5 seconds, until + * it is opened for the first time. After the first open + * it MUST be triggered every 2..95 seconds. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/slab.h> +#include <linux/init.h> + +#include <asm/au1000.h> + + +#ifndef FALSE +# define FALSE (0) +#endif + +#ifndef TRUE +# define TRUE (!FALSE) +#endif + + +//---------[ Hardware Functions ]----------------- + +static void mtx1_trigger_wd (void) +{ + /* + * toggle GPIO2_15 + */ + + u32 tmp = au_readl(GPIO2_DIR); + tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15)); + au_writel (tmp, GPIO2_DIR); +} + +static void mtx1_enable_wd (void) +{ + au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR); +} + +static void mtx1_disable_wd (void) +{ + au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR); +} + + +//---------[ Timer Functions ]----------------- + +static struct timer_list wd_trigger_timer; +static char timer_is_running = FALSE; + +static void wd_timer_callback (unsigned long data) +{ + if (timer_is_running) + mod_timer (&wd_trigger_timer, jiffies + 5 * HZ); + mtx1_trigger_wd (); +} + +static void start_wd_timer (void) +{ + if (!timer_is_running) { + struct timer_list *t = &wd_trigger_timer; + + init_timer (t); + t->function = wd_timer_callback; + t->data = (unsigned long)0L; + t->expires = jiffies + 5 * HZ; // 5 seconds. + add_timer (t); + timer_is_running = TRUE; + } +} + + + +static void stop_wd_timer (void) +{ + if (timer_is_running) { + del_timer(&wd_trigger_timer); + timer_is_running = FALSE; + } +} + + +//---------[ File Functions ]----------------- + +static int mtx1wd_open (struct inode *inode, struct file *file) +{ + if (MINOR(inode->i_rdev)!=WATCHDOG_MINOR) return -ENODEV; + MOD_INC_USE_COUNT; + + // stop the timer, if it is running. It will not be + // started again, until the module is loaded again. + stop_wd_timer(); + + // sleep for 2 seconds, to ensure, that the wd is + // not triggered more often than every 2 seconds. + schedule_timeout (2 * HZ); + + return 0; +} + + +static int mtx1wd_release (struct inode *inode, struct file *file) { + if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) { + } + MOD_DEC_USE_COUNT; + return 0; +} + + +static ssize_t mtx1wd_write (struct file *file, const char *buf, size_t count, loff_t *ppos) { + if (ppos!=&file->f_pos) + return -ESPIPE; + + if (count) { + mtx1_trigger_wd (); + return 1; + } + return 0; +} + + + +static struct file_operations mtx1wd_fops = { + .owner = THIS_MODULE, + .llseek = NULL, + .read = NULL, + .write = mtx1wd_write, + .readdir = NULL, + .poll = NULL, + .ioctl = NULL, + .mmap = NULL, + .open = mtx1wd_open, + .flush = NULL, + .release = mtx1wd_release +}; + + +static struct miscdevice mtx1wd_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &mtx1wd_fops +}; + + + +//---------[ Module Functions ]----------------- + + +void cleanup_module (void) +{ + // stop the timer, if it is running. + stop_wd_timer(); + + misc_deregister(&mtx1wd_miscdev); + + mtx1_disable_wd (); +} + + +int __init init_mtx1_watchdog (void) +{ + printk("MTX-1 watchdog driver\n"); + + mtx1_enable_wd (); + + //-- trigger it for the first time. + //-- We do not exactly know how long it has not been triggered. + mtx1_trigger_wd (); + + misc_register (&mtx1wd_miscdev); + + // start a timer, that calls mtx1_trigger_wd every 5 seconds. + start_wd_timer(); + + return 0; +} + +__initcall(init_mtx1_watchdog); + +MODULE_AUTHOR("Michael Stickel"); +MODULE_DESCRIPTION("Driver for the MTX-1 watchdog"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS;