|
|
|
@ -11,313 +11,195 @@ |
|
|
|
|
* |
|
|
|
|
* You should have received a copy of the GNU General Public License |
|
|
|
|
* along with this program; if not, write to the Free Software |
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
|
|
|
|
* |
|
|
|
|
* Copyright (C) 2006 infineon |
|
|
|
|
* Copyright (C) 2007 John Crispin <blogic@openwrt.org>
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
|
|
|
* |
|
|
|
|
* Copyright (C) 2008 John Crispin <blogic@openwrt.org> |
|
|
|
|
* Based on EP93xx wdt driver |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include <asm/uaccess.h> |
|
|
|
|
#include <linux/errno.h> |
|
|
|
|
#include <linux/proc_fs.h> |
|
|
|
|
#include <linux/ioctl.h> |
|
|
|
|
#include <linux/module.h> |
|
|
|
|
#include <linux/platform_device.h> |
|
|
|
|
#include <linux/watchdog.h> |
|
|
|
|
#include <linux/fs.h> |
|
|
|
|
#include <linux/miscdevice.h> |
|
|
|
|
#include <linux/miscdevice.h> |
|
|
|
|
#include <asm-mips/ifxmips/ifxmips_wdt.h> |
|
|
|
|
#include <linux/watchdog.h> |
|
|
|
|
#include <linux/platform_device.h> |
|
|
|
|
#include <asm/uaccess.h> |
|
|
|
|
#include <asm-mips/ifxmips/ifxmips_cgu.h> |
|
|
|
|
#include <asm-mips/ifxmips/ifxmips.h> |
|
|
|
|
|
|
|
|
|
#define DRVNAME "ifxmips_wdt" |
|
|
|
|
#define IFXMIPS_WDT_PW1 0x00BE0000 |
|
|
|
|
#define IFXMIPS_WDT_PW2 0x00DC0000 |
|
|
|
|
|
|
|
|
|
// TODO remove magic numbers and weirdo macros
|
|
|
|
|
extern unsigned int ifxmips_get_fpi_hz (void); |
|
|
|
|
#ifndef CONFIG_WATCHDOG_NOWAYOUT |
|
|
|
|
static int wdt_ok_to_close = 0; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static int ifxmips_wdt_inuse = 0; |
|
|
|
|
int wdt_timeout = 30; |
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
ifxmips_wdt_enable (unsigned int timeout) |
|
|
|
|
ifxmips_wdt_enable(unsigned int timeout) |
|
|
|
|
{ |
|
|
|
|
unsigned int wdt_cr = 0; |
|
|
|
|
unsigned int wdt_reload = 0; |
|
|
|
|
unsigned int wdt_clkdiv, wdt_pwl, ffpi; |
|
|
|
|
int retval = 0; |
|
|
|
|
|
|
|
|
|
/* clock divider & prewarning limit */ |
|
|
|
|
wdt_clkdiv = 1 << (7 * IFXMIPS_BIU_WDT_CR_CLKDIV_GET(ifxmips_r32(IFXMIPS_BIU_WDT_CR))); |
|
|
|
|
wdt_pwl = 0x8000 >> IFXMIPS_BIU_WDT_CR_PWL_GET(ifxmips_r32(IFXMIPS_BIU_WDT_CR)); |
|
|
|
|
|
|
|
|
|
ffpi = cgu_get_io_region_clock(); |
|
|
|
|
printk("cpu clock = %d\n", ffpi); |
|
|
|
|
|
|
|
|
|
/* caculate reload value */ |
|
|
|
|
wdt_reload = (timeout * (ffpi / wdt_clkdiv)) + wdt_pwl; |
|
|
|
|
|
|
|
|
|
printk(KERN_WARNING DRVNAME ": wdt_pwl=0x%x, wdt_clkdiv=%d, ffpi=%d, wdt_reload = 0x%x\n", |
|
|
|
|
wdt_pwl, wdt_clkdiv, ffpi, wdt_reload); |
|
|
|
|
|
|
|
|
|
if (wdt_reload > 0xFFFF) |
|
|
|
|
{ |
|
|
|
|
printk(KERN_WARNING DRVNAME ": timeout too large %d\n", timeout); |
|
|
|
|
retval = -EINVAL; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Write first part of password access */ |
|
|
|
|
ifxmips_w32(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); |
|
|
|
|
|
|
|
|
|
wdt_cr = ifxmips_r32(IFXMIPS_BIU_WDT_CR); |
|
|
|
|
wdt_cr &= (!IFXMIPS_BIU_WDT_CR_PW_SET(0xff) & |
|
|
|
|
!IFXMIPS_BIU_WDT_CR_PWL_SET(0x3) & |
|
|
|
|
!IFXMIPS_BIU_WDT_CR_CLKDIV_SET(0x3) & |
|
|
|
|
!IFXMIPS_BIU_WDT_CR_RELOAD_SET(0xffff)); |
|
|
|
|
|
|
|
|
|
wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | |
|
|
|
|
IFXMIPS_BIU_WDT_CR_PWL_SET(IFXMIPS_BIU_WDT_CR_PWL_GET(ifxmips_r32(IFXMIPS_BIU_WDT_CR))) | |
|
|
|
|
IFXMIPS_BIU_WDT_CR_CLKDIV_SET(IFXMIPS_BIU_WDT_CR_CLKDIV_GET(ifxmips_r32(IFXMIPS_BIU_WDT_CR))) | |
|
|
|
|
IFXMIPS_BIU_WDT_CR_RELOAD_SET(wdt_reload) | |
|
|
|
|
IFXMIPS_BIU_WDT_CR_GEN); |
|
|
|
|
|
|
|
|
|
ifxmips_w32(wdt_cr, IFXMIPS_BIU_WDT_CR); |
|
|
|
|
|
|
|
|
|
printk("watchdog enabled\n"); |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
return retval; |
|
|
|
|
u32 fpi; |
|
|
|
|
fpi = cgu_get_io_region_clock(); |
|
|
|
|
ifxmips_w32(IFXMIPS_WDT_PW1, IFXMIPS_BIU_WDT_CR); |
|
|
|
|
ifxmips_w32(IFXMIPS_WDT_PW2 | |
|
|
|
|
(0x3 << 26) | // PWL
|
|
|
|
|
(0x3 << 24) | // CLKDIV
|
|
|
|
|
(0x1 << 31) | // enable
|
|
|
|
|
((timeout * (fpi / 0x40000)) + 0x1000), // reload
|
|
|
|
|
IFXMIPS_BIU_WDT_CR); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
ifxmips_wdt_disable (void) |
|
|
|
|
ifxmips_wdt_disable(void) |
|
|
|
|
{ |
|
|
|
|
ifxmips_w32(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); |
|
|
|
|
ifxmips_w32(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2), IFXMIPS_BIU_WDT_CR); |
|
|
|
|
|
|
|
|
|
printk("watchdog disabled\n"); |
|
|
|
|
#ifndef CONFIG_WATCHDOG_NOWAYOUT |
|
|
|
|
wdt_ok_to_close = 0; |
|
|
|
|
#endif |
|
|
|
|
ifxmips_w32(IFXMIPS_WDT_PW1, IFXMIPS_BIU_WDT_CR); |
|
|
|
|
ifxmips_w32(IFXMIPS_WDT_PW2, IFXMIPS_BIU_WDT_CR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* passed LPEN or DSEN */ |
|
|
|
|
void |
|
|
|
|
ifxmips_wdt_enable_feature (int en, int type) |
|
|
|
|
static ssize_t |
|
|
|
|
ifxmips_wdt_write(struct file *file, const char __user *data, size_t len, |
|
|
|
|
loff_t *ppos) |
|
|
|
|
{ |
|
|
|
|
unsigned int wdt_cr = 0; |
|
|
|
|
|
|
|
|
|
ifxmips_w32(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); |
|
|
|
|
size_t i; |
|
|
|
|
|
|
|
|
|
wdt_cr = ifxmips_r32(IFXMIPS_BIU_WDT_CR); |
|
|
|
|
if(!len) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if (en) |
|
|
|
|
#ifndef CONFIG_WATCHDOG_NOWAYOUT |
|
|
|
|
for(i = 0; i != len; i++) |
|
|
|
|
{ |
|
|
|
|
wdt_cr &= (~IFXMIPS_BIU_WDT_CR_PW_SET(0xff)); |
|
|
|
|
wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | type); |
|
|
|
|
} else { |
|
|
|
|
wdt_cr &= (~IFXMIPS_BIU_WDT_CR_PW_SET(0xff) & ~type); |
|
|
|
|
wdt_cr |= IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2); |
|
|
|
|
char c; |
|
|
|
|
if(get_user(c, data + i)) |
|
|
|
|
return -EFAULT; |
|
|
|
|
if(c == 'V') |
|
|
|
|
wdt_ok_to_close = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ifxmips_w32(wdt_cr, IFXMIPS_BIU_WDT_CR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
ifxmips_wdt_prewarning_limit (int pwl) |
|
|
|
|
{ |
|
|
|
|
unsigned int wdt_cr = 0; |
|
|
|
|
|
|
|
|
|
wdt_cr = ifxmips_r32(IFXMIPS_BIU_WDT_CR); |
|
|
|
|
ifxmips_w32(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); |
|
|
|
|
|
|
|
|
|
wdt_cr &= 0xf300ffff; |
|
|
|
|
wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | IFXMIPS_BIU_WDT_CR_PWL_SET(pwl)); |
|
|
|
|
|
|
|
|
|
/* Set reload value in second password access */ |
|
|
|
|
ifxmips_w32(wdt_cr, IFXMIPS_BIU_WDT_CR); |
|
|
|
|
#endif |
|
|
|
|
ifxmips_wdt_enable(wdt_timeout); |
|
|
|
|
return len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
ifxmips_wdt_set_clkdiv (int clkdiv) |
|
|
|
|
{ |
|
|
|
|
unsigned int wdt_cr = 0; |
|
|
|
|
|
|
|
|
|
wdt_cr = ifxmips_r32(IFXMIPS_BIU_WDT_CR); |
|
|
|
|
ifxmips_w32(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); |
|
|
|
|
|
|
|
|
|
wdt_cr &= 0xfc00ffff; |
|
|
|
|
wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | IFXMIPS_BIU_WDT_CR_CLKDIV_SET(clkdiv)); |
|
|
|
|
|
|
|
|
|
/* Set reload value in second password access */ |
|
|
|
|
ifxmips_w32(wdt_cr, IFXMIPS_BIU_WDT_CR); |
|
|
|
|
} |
|
|
|
|
static struct watchdog_info ident = { |
|
|
|
|
.options = WDIOF_MAGICCLOSE, |
|
|
|
|
.identity = "ifxmips Watchdog", |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
ifxmips_wdt_ioctl (struct inode *inode, struct file *file, unsigned int cmd, |
|
|
|
|
ifxmips_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
|
|
|
|
unsigned long arg) |
|
|
|
|
{ |
|
|
|
|
int result = 0; |
|
|
|
|
static int timeout = -1; |
|
|
|
|
unsigned int user_arg; |
|
|
|
|
int ret = -ENOTTY; |
|
|
|
|
|
|
|
|
|
if ((cmd != IFXMIPS_WDT_IOC_STOP) && (cmd != IFXMIPS_WDT_IOC_PING) && (cmd != IFXMIPS_WDT_IOC_GET_STATUS)) |
|
|
|
|
switch(cmd) |
|
|
|
|
{ |
|
|
|
|
if (copy_from_user((void *) &user_arg, (void *) arg, sizeof (int))){ |
|
|
|
|
result = -EINVAL; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch (cmd) |
|
|
|
|
{ |
|
|
|
|
case IFXMIPS_WDT_IOC_START: |
|
|
|
|
if ((result = ifxmips_wdt_enable(user_arg)) < 0) |
|
|
|
|
timeout = -1; |
|
|
|
|
else |
|
|
|
|
timeout = user_arg; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case IFXMIPS_WDT_IOC_STOP: |
|
|
|
|
printk(KERN_INFO DRVNAME ": disable watch dog timer\n"); |
|
|
|
|
ifxmips_wdt_disable(); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case IFXMIPS_WDT_IOC_PING: |
|
|
|
|
if (timeout < 0) |
|
|
|
|
result = -EIO; |
|
|
|
|
else |
|
|
|
|
result = ifxmips_wdt_enable(timeout); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case IFXMIPS_WDT_IOC_GET_STATUS: |
|
|
|
|
user_arg = ifxmips_r32(IFXMIPS_BIU_WDT_SR); |
|
|
|
|
copy_to_user((int*)arg, (int*)&user_arg, sizeof(int)); |
|
|
|
|
case WDIOC_GETSUPPORT: |
|
|
|
|
ret = copy_to_user((struct watchdog_info __user *)arg, &ident, |
|
|
|
|
sizeof(ident)) ? -EFAULT : 0; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case IFXMIPS_WDT_IOC_SET_PWL: |
|
|
|
|
ifxmips_wdt_prewarning_limit(user_arg); |
|
|
|
|
case WDIOC_GETTIMEOUT: |
|
|
|
|
ret = put_user(wdt_timeout, (int __user *)arg); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case IFXMIPS_WDT_IOC_SET_DSEN: |
|
|
|
|
ifxmips_wdt_enable_feature(user_arg, IFXMIPS_BIU_WDT_CR_DSEN); |
|
|
|
|
case WDIOC_SETTIMEOUT: |
|
|
|
|
ret = get_user(wdt_timeout, (int __user*)arg); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case IFXMIPS_WDT_IOC_SET_LPEN: |
|
|
|
|
ifxmips_wdt_enable_feature(user_arg, IFXMIPS_BIU_WDT_CR_LPEN); |
|
|
|
|
case WDIOC_KEEPALIVE: |
|
|
|
|
ifxmips_wdt_enable(wdt_timeout); |
|
|
|
|
ret = 0; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case IFXMIPS_WDT_IOC_SET_CLKDIV: |
|
|
|
|
ifxmips_wdt_set_clkdiv(user_arg); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
printk(KERN_WARNING DRVNAME ": unknown watchdog iotcl\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
return result; |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
ifxmips_wdt_open (struct inode *inode, struct file *file) |
|
|
|
|
ifxmips_wdt_open(struct inode *inode, struct file *file) |
|
|
|
|
{ |
|
|
|
|
if (ifxmips_wdt_inuse) |
|
|
|
|
return -EBUSY; |
|
|
|
|
|
|
|
|
|
ifxmips_wdt_inuse = 1; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
ifxmips_wdt_enable(wdt_timeout); |
|
|
|
|
printk("ifxmips_wdt: activated"); |
|
|
|
|
return nonseekable_open(inode, file); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
ifxmips_wdt_release (struct inode *inode, struct file *file) |
|
|
|
|
static int ifxmips_wdt_release(struct inode *inode, struct file *file) |
|
|
|
|
{ |
|
|
|
|
ifxmips_wdt_inuse = 0; |
|
|
|
|
|
|
|
|
|
#ifndef CONFIG_WATCHDOG_NOWAYOUT |
|
|
|
|
if(wdt_ok_to_close) |
|
|
|
|
ifxmips_wdt_disable(); |
|
|
|
|
else |
|
|
|
|
#endif |
|
|
|
|
printk(KERN_INFO "watchdog closed without warning, rebooting system\n"); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
ifxmips_wdt_register_proc_read (char *buf, char **start, off_t offset, int count, |
|
|
|
|
int *eof, void *data) |
|
|
|
|
{ |
|
|
|
|
int len = 0; |
|
|
|
|
|
|
|
|
|
len += sprintf (buf + len, "IFXMIPS_BIU_WDT_PROC_READ\n"); |
|
|
|
|
len += sprintf (buf + len, "IFXMIPS_BIU_WDT_CR(0x%08x) : 0x%08x\n", |
|
|
|
|
(unsigned int)IFXMIPS_BIU_WDT_CR, ifxmips_r32(IFXMIPS_BIU_WDT_CR)); |
|
|
|
|
len += sprintf (buf + len, "IFXMIPS_BIU_WDT_SR(0x%08x) : 0x%08x\n", |
|
|
|
|
(unsigned int)IFXMIPS_BIU_WDT_SR, ifxmips_r32(IFXMIPS_BIU_WDT_SR)); |
|
|
|
|
|
|
|
|
|
*eof = 1; |
|
|
|
|
|
|
|
|
|
return len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const struct file_operations ifxmips_wdt_fops = { |
|
|
|
|
.owner = THIS_MODULE, |
|
|
|
|
.llseek = no_llseek, |
|
|
|
|
.write = ifxmips_wdt_write, |
|
|
|
|
.ioctl = ifxmips_wdt_ioctl, |
|
|
|
|
.open = ifxmips_wdt_open, |
|
|
|
|
.release = ifxmips_wdt_release, |
|
|
|
|
// .write = at91_wdt_write,
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static struct miscdevice ifxmips_wdt_miscdev = { |
|
|
|
|
.minor = WATCHDOG_MINOR, |
|
|
|
|
.name = "ifxmips_wdt", |
|
|
|
|
.name = "watchdog", |
|
|
|
|
.fops = &ifxmips_wdt_fops, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
ifxmips_wdt_probe (struct platform_device *pdev) |
|
|
|
|
ifxmips_wdt_probe(struct platform_device *dev) |
|
|
|
|
{ |
|
|
|
|
int ret = misc_register(&ifxmips_wdt_miscdev); |
|
|
|
|
if (ret) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
create_proc_read_entry(DRVNAME, 0, NULL, ifxmips_wdt_register_proc_read, NULL); |
|
|
|
|
|
|
|
|
|
printk(KERN_INFO DRVNAME ": ifxmips watchdog loaded\n"); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
int err; |
|
|
|
|
err = misc_register(&ifxmips_wdt_miscdev); |
|
|
|
|
if(err) |
|
|
|
|
printk("ifxmips_wdt: error creating device\n"); |
|
|
|
|
else |
|
|
|
|
printk("ifxmips_wdt: loaded\n"); |
|
|
|
|
return err; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
ifxmips_wdt_remove (struct platform_device *pdev) |
|
|
|
|
ifxmips_wdt_remove(struct platform_device *dev) |
|
|
|
|
{ |
|
|
|
|
ifxmips_wdt_disable(); |
|
|
|
|
misc_deregister(&ifxmips_wdt_miscdev); |
|
|
|
|
remove_proc_entry(DRVNAME, NULL); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct |
|
|
|
|
platform_driver ifxmips_wdt_driver = { |
|
|
|
|
|
|
|
|
|
static struct platform_driver ifxmips_wdt_driver = { |
|
|
|
|
.probe = ifxmips_wdt_probe, |
|
|
|
|
.remove = ifxmips_wdt_remove, |
|
|
|
|
.driver = { |
|
|
|
|
.name = DRVNAME, |
|
|
|
|
.name = "ifxmips_wdt", |
|
|
|
|
.owner = THIS_MODULE, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
int __init |
|
|
|
|
ifxmips_wdt_init_module (void) |
|
|
|
|
static int __init |
|
|
|
|
init_ifxmips_wdt(void) |
|
|
|
|
{ |
|
|
|
|
int ret = platform_driver_register(&ifxmips_wdt_driver); |
|
|
|
|
if (ret) |
|
|
|
|
printk(KERN_INFO DRVNAME ": Error registering platfom driver!"); |
|
|
|
|
if(ret) |
|
|
|
|
printk(KERN_INFO "ifxmips_wdt: error registering platfom driver!"); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
ifxmips_wdt_cleanup_module (void) |
|
|
|
|
static void __exit |
|
|
|
|
exit_ifxmips_wdt(void) |
|
|
|
|
{ |
|
|
|
|
platform_driver_unregister(&ifxmips_wdt_driver); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
module_init(ifxmips_wdt_init_module); |
|
|
|
|
module_exit(ifxmips_wdt_cleanup_module); |
|
|
|
|
module_init(init_ifxmips_wdt); |
|
|
|
|
module_exit(exit_ifxmips_wdt); |
|
|
|
|
|
|
|
|
|
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); |
|
|
|
|
MODULE_DESCRIPTION("Watchdog driver for infineon ifxmips family"); |
|
|
|
|
MODULE_DESCRIPTION("ifxmips Watchdog"); |
|
|
|
|
MODULE_LICENSE("GPL"); |
|
|
|
|
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
|
|
|
|