parent
783bb0e81c
commit
f086a123c9
@ -1,323 +1,205 @@ |
||||
/*
|
||||
* 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. |
||||
* 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. |
||||
*
|
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* 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>
|
||||
* 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) 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 <asm-mips/ifxmips/ifxmips_wdt.h> |
||||
#include <linux/miscdevice.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; |
||||
size_t i; |
||||
|
||||
ifxmips_w32(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); |
||||
if(!len) |
||||
return 0; |
||||
|
||||
wdt_cr = ifxmips_r32(IFXMIPS_BIU_WDT_CR); |
||||
|
||||
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, |
||||
unsigned long arg) |
||||
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; |
||||
|
||||
if ((cmd != IFXMIPS_WDT_IOC_STOP) && (cmd != IFXMIPS_WDT_IOC_PING) && (cmd != IFXMIPS_WDT_IOC_GET_STATUS)) |
||||
{ |
||||
if (copy_from_user((void *) &user_arg, (void *) arg, sizeof (int))){ |
||||
result = -EINVAL; |
||||
goto out; |
||||
} |
||||
} |
||||
int ret = -ENOTTY; |
||||
|
||||
switch (cmd) |
||||
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)); |
||||
break; |
||||
|
||||
case IFXMIPS_WDT_IOC_SET_PWL: |
||||
ifxmips_wdt_prewarning_limit(user_arg); |
||||
case WDIOC_GETSUPPORT: |
||||
ret = copy_to_user((struct watchdog_info __user *)arg, &ident, |
||||
sizeof(ident)) ? -EFAULT : 0; |
||||
break; |
||||
|
||||
case IFXMIPS_WDT_IOC_SET_DSEN: |
||||
ifxmips_wdt_enable_feature(user_arg, IFXMIPS_BIU_WDT_CR_DSEN); |
||||
case WDIOC_GETTIMEOUT: |
||||
ret = put_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_SETTIMEOUT: |
||||
ret = get_user(wdt_timeout, (int __user*)arg); |
||||
break; |
||||
|
||||
case IFXMIPS_WDT_IOC_SET_CLKDIV: |
||||
ifxmips_wdt_set_clkdiv(user_arg); |
||||
case WDIOC_KEEPALIVE: |
||||
ifxmips_wdt_enable(wdt_timeout); |
||||
ret = 0; |
||||
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); |
||||
|
@ -1,48 +0,0 @@ |
||||
/*
|
||||
* 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. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* 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) 2005 infineon |
||||
* Copyright (C) 2007 John Crispin <blogic@openwrt.org>
|
||||
* |
||||
*/ |
||||
|
||||
#ifndef IFXMIPS_WDT_H |
||||
#define IFXMIPS_WDT_H |
||||
|
||||
/* IFXMips wdt ioctl control */ |
||||
#define IFXMIPS_WDT_IOC_MAGIC 0xc0 |
||||
#define IFXMIPS_WDT_IOC_START _IOW(IFXMIPS_WDT_IOC_MAGIC, 0, int) |
||||
#define IFXMIPS_WDT_IOC_STOP _IO(IFXMIPS_WDT_IOC_MAGIC, 1) |
||||
#define IFXMIPS_WDT_IOC_PING _IO(IFXMIPS_WDT_IOC_MAGIC, 2) |
||||
#define IFXMIPS_WDT_IOC_SET_PWL _IOW(IFXMIPS_WDT_IOC_MAGIC, 3, int) |
||||
#define IFXMIPS_WDT_IOC_SET_DSEN _IOW(IFXMIPS_WDT_IOC_MAGIC, 4, int) |
||||
#define IFXMIPS_WDT_IOC_SET_LPEN _IOW(IFXMIPS_WDT_IOC_MAGIC, 5, int) |
||||
#define IFXMIPS_WDT_IOC_GET_STATUS _IOR(IFXMIPS_WDT_IOC_MAGIC, 6, int) |
||||
#define IFXMIPS_WDT_IOC_SET_CLKDIV _IOW(IFXMIPS_WDT_IOC_MAGIC, 7, int) |
||||
|
||||
/* password 1 and 2 */ |
||||
#define IFXMIPS_WDT_PW1 0x000000BE |
||||
#define IFXMIPS_WDT_PW2 0x000000DC |
||||
|
||||
#define IFXMIPS_WDT_CLKDIV0_VAL 1 |
||||
#define IFXMIPS_WDT_CLKDIV1_VAL 64 |
||||
#define IFXMIPS_WDT_CLKDIV2_VAL 4096 |
||||
#define IFXMIPS_WDT_CLKDIV3_VAL 262144 |
||||
#define IFXMIPS_WDT_CLKDIV0 0 |
||||
#define IFXMIPS_WDT_CLKDIV1 1 |
||||
#define IFXMIPS_WDT_CLKDIV2 2 |
||||
#define IFXMIPS_WDT_CLKDIV3 3 |
||||
|
||||
#endif |
Loading…
Reference in new issue