1. 看门狗概述
看门狗其实就是一个定时器,当该定时器溢出前必须对看门狗进行"喂狗“(重新计时),如果不这样做,定时器溢出后则将复位CPU。因此,看门狗通常用于对处于异常状态(不能实现“喂狗”)的CPU进行复位。
S3C2440看门狗
s3c2440的看门狗的原理框图如下
可以看出,看门狗定时器的频率由PCLK提供,其预分频器最大取值为255+1;另外,通过MUX,可以进一步降低频率。 定时器采用递减模式,一旦到0,则可以触发看门狗中断以及RESET复位信号。
看门狗定时器的频率的计算公式如下:
2. 看门狗驱动
框架图:
2.1平台设备模型开发底层设备驱动的大致流程
2.2模块注册以及probe函数
static struct platform_driver s3c2410wdt_driver = {
.probe = s3c2410wdt_probe,
.remove = s3c2410wdt_remove,
.shutdown = s3c2410wdt_shutdown,
.suspend = s3c2410wdt_suspend,
.resume = s3c2410wdt_resume,
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-wdt",//设备名,要和设备平台注册的名字相同
},
};
static char banner[] __initdata =
KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
static int __init watchdog_init(void){
printk(banner);
return platform_driver_register(&s3c2410wdt_driver);
}
module_init(watchdog_init)
模块的注册函数很简单,直接调用了 platform的驱动注册platform_driver_register。
该函数在注册时会调用驱动的probe方法,也即s3c2410wdt_probe函数。
我们来看下这个函数:
static int s3c2410wdt_probe(struct platform_device *pdev)
{
struct resource *res;
struct device *dev;
unsigned int wtcon;
int started = 0;
int ret;
int size;
DBG("%s: probe=%p\n", __func__, pdev);
dev = &pdev->dev;
wdt_dev = &pdev->dev;
/* get the memory region for the watchdog timer */
/*获取平台资源,寄存器地址范围*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(dev, "no memory resource specified\n");
return -ENOENT;
}
/*内存申请*/
size = (res->end - res->start) + 1;
wdt_mem = request_mem_region(res->start, size, pdev->name);
if (wdt_mem == NULL) {
dev_err(dev, "failed to get memory region\n");
ret = -ENOENT;
goto err_req;
}
/*内存映射*/
wdt_base = ioremap(res->start, size);
if (wdt_base == NULL) {
dev_err(dev, "failed to ioremap() region\n");
ret = -EINVAL;
goto err_req;
}
DBG("probe: mapped wdt_base=%p\n", wdt_base);
/*获取平台资源,看门狗定时器中断号*/
wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (wdt_irq == NULL) {
dev_err(dev, "no irq resource specified\n");
ret = -ENOENT;
goto err_map;
}
/*注册看门狗定时器中断*/
ret =