本次来开发自己的watchdog驱动程序.watchdog是系统的硬件守护者,在Linux里面的守护进程则是软件守护者,两者维护的对象有一些差异,这里先暂不做讨论,直接说看门狗的驱动:
在三星平台片上集成了看门狗外设,这种外设只有4个寄存器,别看寄存器比较少,但是它使用的频率是很高的,从结构上看,可以把它看作一个定时器,当然,看门狗也可以作为定时器使用,我们在驱动代码里面已经写了一个开关,开关为0时,作为看门狗复位使用,开关为1时,作为定时器使用,因为,片上已经集成了很多专门的定时器,所以,一般没必要用看门狗去做定时器用,所以,我们写的这个驱动里面没有实现ioctl,在ioctl方法里实际上可以设置看门狗模式,超时时间等等,暂时没有写.我们来看一下三星官方提供的datasheet:
从上图可以看出,一共有4个寄存器,这4个寄存器的作用可以参考下图:
结合图和datasheet,可以知道寄存器的作用如下:
WTCON: 看门狗配置寄存器
WTDAT: 看门狗数据寄存器
WTCNT: 看门狗计数寄存器
WTCLRINT:看门狗清中断寄存器
我们这个驱动主要是实现的是看门狗复位,没有用作定时器,所以WTCLRINT不需要用到,所以没有配置,它的作用就是在配置为中断模式时,随便往这个寄存器写一个不超过0xffffffff的值,就可以清除中断,我们看看官方怎们说的:
"你能使用WTCLRINT寄存器清除中断, 中断服务函数有责任在中断服务完成之后清除中断,方法是写任意值到这个寄存器,不允许读取这个寄存器"(虽然说是任意值,但不要超过0xffffffff,否则会寄存器溢出,因为它是32bit寄存器)
顾名思义喽,如果配制成中断模式,在中断服务函数里执行完后,要往此寄存器写一个值,以清除中断.
下面,我们来看一下其它几个寄存器都是干嘛的:
WTCON配置寄存器只使用了低16位,第0为配置重启是否有效,第2位配置中断是否有效,第[4:3]这两位配置二级时钟分频,第5位是看门狗使能位,第[15:8]这8位是看门狗时钟预分频位,可以配置为0~255,因为配置中不允许是0,所以,实际设计当中是[15:8] + 1,也就是说,配置的数再加1,比如寄存器配置的是255,那么芯片会自动加1,也就是256.从而可以避免是0这种情况发生.
然后接下来是WTDAT和WTCNT寄存器:
它们的作用是WTDAT存储重载数值,WTCNT则是存储计数器值,这个值会递减,当递减到0,正常情况下,则WTDAT的值会重载入WTCNT,从上图可以看出,它们只用到了寄存器的低16位,也就是说其最大值是65535(0xffff).
好了了解了寄存器之后,我们就直接上代码,代码里关键地方有写注释,所以设计思路就不讲了,直接看代码(参考s3c2410_wdt.c):
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cpufreq.h>
#include <linux/err.h>
#include <linux/of.h>
#include <mach/map.h>
#include <plat/regs-watchdog.h>
#undef S3C_VA_WATCHDOG
#define S3C_VA_WATCHDOG (0)
#ifdef CONFIG_CPU_FREQ
#undef CONFIG_CPU_FREQ
#endif
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
struct wdt_object{
bool nowayout; // 是否允许看门狗被关闭
int tmr_margin; // 默认喂狗时间
int tmr_atboot; // 系统启动时是否启动看门狗
int soft_noboot; // 看门狗工作模式,0:复位 1,中断
unsigned int wdt_count;
void __iomem *wdt_base;
struct device *wdt_dev;
struct resource *wdt_mem;
struct resource *wdt_irq;
struct clk *wdt_clock;
};
struct wdt_object *wdt_drv;
static