版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38696651/article/details/89431178
本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记
一. watchdog硬件信息
watchdog的device信息如下:
static struct resource s3c_wdt_resource[] =
{
[0] = {
.start = S3C24XX_PA_WATCHDOG,
.end = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_WDT,
.end = IRQ_WDT,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device s3c_device_wdt = {
.name = "s3c2410-wdt",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_wdt_resource),
.resource = s3c_wdt_resource,
};
- 控制寄存器: WTCON,地址是 0x53000000
- 初始时间寄存器: WTDAT,地址是 0x53000004
- 计数寄存器: WTCNT,地址是 0x53000008
- 中断号是:IRQ_WDT,就是1
二. watchdog device 注册
调用platform_device_register注册平台s3c_device_wdt设备,设备名称是: “s3c2410-wdt”
三. watchdog driver 注册
- watchdog的driver结构体如下:
static struct platform_driver s3c2410wdt_driver =
{
.probe = s3c2410wdt_probe,
.remove = __devexit_p(s3c2410wdt_remove),
.shutdown = s3c2410wdt_shutdown,
.suspend = s3c2410wdt_suspend,
.resume = s3c2410wdt_resume,
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-wdt",
},
};
- 注册watchdog driver
static int __init watchdog_init(void)
{
return platform_driver_register(&s3c2410wdt_driver);
}
三. watchdog driver的probe函数
- 获取mem资源并进行io映射
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;
}
- 获取中断号,申请中断
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 = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
if (ret != 0)
{
dev_err(dev, "failed to install irq (%d)\n", ret);
goto err_map;
}
- 获取watchdog时钟,并使能时钟
wdt_clock = clk_get(&pdev->dev, "watchdog");
if (IS_ERR(wdt_clock))
{
dev_err(dev, "failed to find watchdog clock source\n");
ret = PTR_ERR(wdt_clock);
goto err_irq;
}
clk_enable(wdt_clock);
- 设置定时超时时间
if (s3c2410wdt_set_heartbeat(tmr_margin))
{
started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
if (started == 0)
dev_info(dev,"tmr_margin value out of range, default %d used\n",
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
else
dev_info(dev, "default timer value is out of range, ""cannot start\n");
}
如果tmr_margin太大,超出了范围,就使用默认值15,就是15m超时。
- 启动watchdog定时器
s3c2410wdt_start();
四. 设置定时时间
设置定时时间调用的函数是:s3c2410wdt_set_heartbeat
- 获取watchdog时钟
freq = clk_get_rate(wdt_clock);
- 除以分频系数
freq /= 128;
这里的分频系数写死成了128,实际上可以通过寄存器设置。
- 计算count值
count = timeout * freq;
假设时钟频率为1kHz,即1s中计数1000次,那么15s超时,15s内计数15000次。
找到预分频系数
if (count >= 0x10000)
{
for (divisor = 1; divisor <= 0x100; divisor++)
{
if ((count / divisor) < 0x10000)
break;
}
if ((count / divisor) >= 0x10000)
{
dev_err(wdt_dev, "timeout %d too big\n", timeout);
return -EINVAL;
}
}
预分频系数divisor的取值为:count / divisor) < 0x10000
WTCNT寄存器保存的count的最大值即为0x10000,所以要小于0x10000
得到count值
count /= divisor;
- 将预分频的数值写入寄存器
/* update the pre-scaler */
wtcon = readl(wdt_base + S3C2410_WTCON);
wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
writel(wtcon, wdt_base + S3C2410_WTCON);
预分频的值为0 ~ 255
将count值写入data装在寄存器
writel(count, wdt_base + S3C2410_WTDAT);
count值为0 ~ (0x10000 - 1)
五.启动watchdog定时器
- 首先若定时器已经启动了,先停止定时器。
__s3c2410wdt_stop();
- 启动定时器,设置分频系数,预分频系统在上一步已经设置到寄存器中。分频系数是128
#define S3C2410_WTCON_ENABLE (1<<5)
wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
- 如果soft_noboot设置成了1,把watchdog定时器当成普通的定时器来使用,这个时候要使能中断,并且关掉watchdog定时器的复位功能。
wtcon |= S3C2410_WTCON_INTEN;
wtcon &= ~S3C2410_WTCON_RSTEN;
六. 关闭watchdog定时器
WTCON寄存器的第5位设置为0,第0位设置为0
wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
writel(wtcon, wdt_base + S3C2410_WTCON);
七. watchdog定时器的中断
定时器中断主要是把count值重新写到 WTDAT寄存器
writel(wdt_count, wdt_base + S3C2410_WTCNT);