刚才终于把bfin548 WATCHGDOG给弄出来了,功能实现的很简单,就是给用户层应用程序提供一个接口,
时间随自己去定,可以设置看门狗的时间,还有就是喂狗的功能。bfin处理器的WATCHDOG做的还是比较简单的,实现起来也特别容易,就只有简单的三个寄存器:WDOG_CNT,WDOG_STAT,WDOG_CTL。WDOG_CNT就是写驱动的时候要进行设置的(就是超时时间),WDOG_STAT就是WDOG_CNT的一个副本,实际会进行自减功能的寄存器是WDOG_STAT,当WDOG_STAT减到零的时候就会触发看门狗事件。当然你必须打开看门狗这个功能才有效,也就是对WDOG_CTL进行设置,WDEN这个值只要不设置成0xad0,那WDOG_STAT就会进行自减。
还有一点就是怎么将WDOG_CNT复制到WDOG_STAT,硬件手册上面是写了两种方法:
1.先disable watchdog timer,后写WDOG_CNT,WDOG_CNT就会下载到WDOG_STAT。(程序代码中用的是方法一)
2.先enable watchdog timer,再写WDOG_STAT,WDOG_STAT就会下载到WDOG_CNT。
再有一点就是喂狗的方法,也就是把WDOG_CNT复制到WDOG_STAT,就只要写一个任意的值到WDOG_STAT就可以了。
别看一个watchdog小驱动,所谓麻雀虽小,确实五脏俱全呀,这里面综合了字符设备,混杂设备,平台设备驱动,确实是个值得学习一下的。
code:
/*************
*bf532
*
* *********************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "bfin_wdt.h"
#define WATCHDOG_NAME "bfin-wdt"
#define YONGDEBUG 1
static unsigned int timeout = WATCHDOG_TIMEOUT;
static DEFINE_SPINLOCK(bfin_wdt_spinlock);
static int bfin_wdt_open(struct inode *inode, struct file *file);
static int bfin_wdt_release(struct inode *inode, struct file *file);
static ssize_t bfin_wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos);
static long bfin_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int bfin_wdt_start(void);
static int bfin_wdt_stop(void);
static int bfin_wdt_check(void);
static int bfin_wdt_set_timeout(unsigned long t);
static int bfin_wdt_keepalive(void);
// enable watchdog
static int bfin_wdt_start(void)
{
bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET);
return 0;
}
// disable watchdog
static int bfin_wdt_stop(void)
{
bfin_write_WDOG_CTL(WDEN_DISABLE);//while WDOG_STAT reach to 0, cpu reset
return 0;
}
static int bfin_wdt_check(void)
{
return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE);
}
/**
*set watchdog value
* ***/
static int bfin_wdt_set_timeout(unsigned long t)
{
unsigned long cnt;
unsigned long flags;
unsigned long sys_clk = get_sclk();//get the system clock
cnt = t ;
printk(KERN_INFO "get_sclk(), cnt = %lu \n", cnt);
spin_lock_irqsave(&bfin_wdt_spinlock, flags);
{
int ret = bfin_wdt_check();
bfin_wdt_stop();
bfin_write_WDOG_CNT(cnt);
printk(KERN_INFO "bfin_wdt_check() ret = %d\n", ret);
if(!ret){
bfin_wdt_start();
}
#ifdef YONG
{
unsigned long val;
val = bfin_read_WDOG_STAT();
printk(KERN_INFO "STAT val = 0x%lx \n", val);
val = bfin_read_WDOG_CTL();
printk(KERN_INFO "CTL val = 0x%lx \n", val);
val = bfin_read_SIC_IMASK0();
printk(KERN_INFO "SIC_IMASK0 val = 0x%lx \n", val);
}
#endif
}
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
timeout = t;
printk(KERN_INFO "bfin_wdt_set_timeout() return 0----\n");
return 0;
}
/****************
*write(any value) to WDOG_STAT lead to reload the count value from WDOG_CNT to
*WDOG_STAT
* **************feed watchdog ********/
static int bfin_wdt_keepalive(void)
{
bfin_write_WDOG_STAT(0);
return 0;
}
#ifndef CONFIG_PM//power manager
static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
return 0;
}
static int bfin_wdt_resume(struct platform_device *pdev)
{
return 0;
}
#elif
#define bfin_wdt_suspend NULL
#define bfin_wdt_resume NULL
#endif
static int bfin_wdt_open(struct inode *inode, struct file *file)
{
#if 0
if(test_and_set_bit(0, &open_check)){
printk(KERN_WARNING "wachdog is busying\n");
return -EBUSY;
}
if(nowayout){
__module_get(THIS_MODULE);
}
bfin_wdt_keepalive();
bfin_wdt_start();
if((ret = nonseekable_open(inode, file)) < 0){
printk(KERN_ERR "nonseekable_open() < 0\n");
return -1;
}
#endif
return 0;
}
static int bfin_wdt_release(struct inode *inode, struct file *file)
{
#if 0
if(expect_close == 42){
bfin_wdt_stop();
}else{
printk(KERN_INFO "unexpected close, not stopping watchdog!\n");
vfin_wdt_keepalive();
}
expect_close = 0;
clear_bit(0, &open_check);
#endif
return 0;
}
static ssize_t bfin_wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
{
return 0;
}
static long bfin_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
switch(cmd){
case WATCHDOG_ENABLE:
case WATCHDOG_CNT:
{
#ifdef YONGDEBUG
printk(KERN_INFO "set watchdog cnt--------------\n");
#endif
int new_timeout;
if(get_user(new_timeout, p))//get user space p value to kernel space new_timeout
return -EFAULT;
#ifdef YONGDEBUG
printk(KERN_INFO "newtimeout = %d--------------\n", new_timeout);
#endif
if(bfin_wdt_set_timeout(new_timeout) < 0){
#ifdef YONGDEBUG
printk(KERN_INFO "bfin_wdt_set_timeout() < 0----\n");
#endif
return -EINVAL;
}
#ifdef YONGDEBUG
#endif
break;
}
case WATCHDOG_FEED:
#ifdef YONGDEBUG
printk(KERN_INFO "feed watchdog ---------------\n");
#endif
bfin_wdt_keepalive();
break;
case WATCHDOG_STAT:
{
unsigned long val;
val = bfin_read_WDOG_STAT();
#ifdef YONGDEBUG
printk(KERN_INFO "STAT val = 0x%lx \n", val);
#endif
break;
}
default:
return -EINVAL;
}
return 0;
}
static struct file_operations bfin_wdt_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = bfin_wdt_open,
.release = bfin_wdt_release,
.write = bfin_wdt_write,
.unlocked_ioctl = bfin_wdt_ioctl,
};
static struct miscdevice bfin_wdt_miscdev =
{
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &bfin_wdt_fops,
};
#if 0
static struct watchdog_info bfin_wdt_info = {
.identity = "Blackfin Watchdog",
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
};
#endif
static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
{
if(code == SYS_DOWN || code == SYS_HALT){
bfin_wdt_stop();
}
return NOTIFY_DONE;
}
static struct notifier_block bfin_wdt_notifier = {
.notifier_call = bfin_wdt_notify_sys,
};
static int __devinit bfin_wdt_probe(struct platform_device *pdev)
{
int ret;
#ifdef YONG
unsigned long val = bfin_read_SIC_IMASK0();
// printk(KERN_INFO "read SIC_IMASK0 val1 = 0x%lx \n", val);
val |= 0x800000;
// printk(KERN_INFO "read SIC_IMASK0 val2 = 0x%lx \n", val);
bfin_write_SIC_IMASK0(val);
val = bfin_read_SIC_IMASK0();
printk(KERN_INFO "read SIC_IMASK0 val3 = 0x%lx \n", val);
val = bfin_read_SYSCR();
printk(KERN_INFO "read SYSCR val = 0x%lx \n", val);
bfin_write_SWRST(0x4000);
val = bfin_read_SWRST();
printk(KERN_INFO "read SWRST val = 0x%lx \n", val);
#endif
#ifdef YONGDEBUG
printk(KERN_INFO "begin to bfin_wdt_probe()----\n");
#endif
ret = register_reboot_notifier(&bfin_wdt_notifier);
if(ret){
printk(KERN_INFO "cannot register reboot notifier (err = %d)\n", ret);
return ret;
}
ret = misc_register(&bfin_wdt_miscdev);
if(ret){
printk(KERN_ERR "cannot register miscdev on minor = %d (err = %d)\n", WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&bfin_wdt_notifier);
return ret;
}
#ifdef YONGDEBUG
printk(KERN_INFO "end to bfin_wdt_probe()----\n");
#endif
return 0;
}
static int __devexit bfin_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&bfin_wdt_miscdev);
unregister_reboot_notifier(&bfin_wdt_notifier);
return 0;
}
static struct platform_device *bfin_wdt_device;
static struct platform_driver bfin_wdt_driver = {
.probe = bfin_wdt_probe,
.remove = __devexit_p(bfin_wdt_remove),
.suspend = bfin_wdt_suspend,
.resume = bfin_wdt_resume,
.driver = {
.name = WATCHDOG_NAME,
.owner = THIS_MODULE,
},
};
static int __init bfin_wdt_init(void)
{
int ret;
//if(bfin_wdt_set_timeout(timeout)){
// return -EINVAL;
//}
ret = platform_driver_register(&bfin_wdt_driver);
if(ret){
printk(KERN_ERR "unable to register driver\n");
return ret;
}
bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0);
if(IS_ERR(bfin_wdt_device)){
printk(KERN_ERR "unable to register device\n");
platform_driver_unregister(&bfin_wdt_driver);
return PTR_ERR(bfin_wdt_device);
}
#ifdef YONGDEBUG
printk(KERN_INFO "end bfin_wdt_init()----\n");
#endif
return 0;
}
static void __exit bfin_wdt_exit(void)
{
platform_device_unregister(bfin_wdt_device);
platform_driver_unregister(&bfin_wdt_driver);
}
module_init(bfin_wdt_init);
module_exit(bfin_wdt_exit);
MODULE_AUTHOR("jackjiang yong253535551@163.com");
MODULE_DESCRIPTION("Blackfin532 Watchdog Device Driver");
MODULE_LICENSE("GPL");
#ifndef __BFIN_WDT_H__
#define __BFIN_WDT_H__
#if 0
/*************
*watchdog register
*
* *****************/
#define WDOG_CNT 0xeec00204 //Watchdog Count Register
#define WDOG_STAT 0xffc00208 //Watchdog Statuc Register
#define WDOG_CTL 0xffc00200 //Watchdog Control Register
#endif
#if 0
/***********
*watchdog read and write register
* ****************/
# define bfin_read_WDOG_CTL() bfin_read_WDOGA_CTL()
# define bfin_read_WDOG_CNT() bfin_read_WDOGA_CNT()
# define bfin_read_WDOG_STAT() bfin_read_WDOGA_STAT()
# define bfin_write_WDOG_CTL(x) bfin_write_WDOGA_CTL(x)
# define bfin_write_WDOG_CNT(x) bfin_write_WDOGA_CNT(x)
# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
#endif
/************
*we define some special value
* **********************/
/* Bit in SWRST that indicates boot caused by watchdog */
#define SWRST_RESET_WDOG 0x4000
/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
#define WDOG_EXPIRED 0x8000
/* Masks for WDEV field in WDOG_CTL register */
#define ICTL_RESET 0x0
#define ICTL_NMI 0x2
#define ICTL_GPI 0x4
#define ICTL_NONE 0x6
#define ICTL_MASK 0x6
/* Masks for WDEN field in WDOG_CTL register */
#define WDEN_MASK 0x0FF0
#define WDEN_ENABLE 0x0000
#define WDEN_DISABLE 0x0AD0
/* some defaults */
#define WATCHDOG_TIMEOUT 20
#define WATCHDOG_ENABLE 0x01
#define WATCHDOG_DISABLE 0x02
#define WATCHDOG_FEED 0x03
#define WATCHDOG_CNT 0x04
#define WATCHDOG_STAT 0x05
#endif