Chinaunix首页 | 论坛 | 博客
  • 博客访问: 176332
  • 博文数量: 76
  • 博客积分: 287
  • 博客等级: 二等列兵
  • 技术积分: 810
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 18:23
文章分类

全部博文(76)

文章存档

2018年(1)

2017年(1)

2015年(1)

2014年(31)

2013年(34)

2012年(3)

2011年(3)

2010年(2)

我的朋友

分类: LINUX

2010-11-25 12:01:58

  刚才终于把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

#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



阅读(1419) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~