s3c2440看门狗驱动,附带测试程序,在tq2440板子测试成功
来源:互联网 发布:重置网络命令 编辑:程序博客网 时间:2024/04/27 23:04
这个驱动被我注释到天花乱坠,确实要看懂它得去学平台设备驱动跟锁机制,所以耽搁了一小段时间,在加载进板子前需要将之前板子的内核里边的看门狗驱动给去掉,必须先在内核目录下make munuconfig,然后在Device driver里边的Watchdog 的星号给去掉,然后重新编译内核烧进板子里。直接上驱动:Watchdog.c:
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <mach/map.h>
#include <plat/regs-watchdog.h>
#define S3C_VA_WATCHDOG (0)
#define PFX "s3c2410-wdt:"
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
static int nowayout = WATCHDOG_NOWAYOUT;//nowayout与CONFIG_WATCHDOG_NOWAYOUT配置相关,其一旦配置应用层调用close函数将不能关闭看门狗
static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;//默认的喂狗时间
static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;//关于tmr_atboot,要想系统一上电自动使能看门狗,就为1。最好使用0,由于我们想通过open函数来打开看门狗
static int soft_noboot;//soft_noboot为1时看门狗将作为一般的中断定时器使用,为0时作为可复位电路的看门狗,默认为0
static int debug; ////调式模式
module_param(tmr_margin, int, 0);
module_param(tmr_atboot, int, 0);
module_param(nowayout, int, 0);
module_param(soft_noboot, int, 0);
module_param(debug, int, 0);
//下面的这些没什么大的作用,就是为了做参数描述
MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default="
__MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default="
__MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
"0 to reboot (default depends on ONLY_TESTING)");
MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
static unsigned long open_lock;
static struct device *wdt_dev;
//用来保存watchdog的IO端口占用的IO空间和经过虚拟映射后的内存地址
static struct resource *wdt_mem;
static void __iomem *wdt_base;
static struct resource *wdt_irq;
//保存从平台时钟队列中获取watchdog的时钟
static struct clk *wdt_clock;
//用于保存经计算后得到的计数寄存器WTCNT的计数值
static unsigned int wdt_count;
static char expect_close;
static DEFINE_SPINLOCK(wdt_lock);
#define DBG(msg...) \
do { \
if (debug) \
printk(KERN_INFO msg); \
} while (0) //打印调试信息
static void s3c2410wdt_keepalive(void) //喂狗
{
spin_lock(&wdt_lock);//获取自旋锁保护临界区资源
writel(wdt_count, wdt_base + S3C2410_WTCNT);//往计数寄存器WTCNT重新写入计数值
spin_unlock(&wdt_lock);//释放自旋锁
}
static void __s3c2410wdt_stop(void)
{
unsigned long wtcon;
//停止看门狗定时器
wtcon = readl(wdt_base + S3C2410_WTCON);
wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
writel(wtcon, wdt_base + S3C2410_WTCON);//wtcon->wdt_base + s3c2410_WTCON_RSTEN
}
static void s3c2410wdt_stop(void)
{
spin_lock(&wdt_lock);//获取自旋锁保护临界区资源
__s3c2410wdt_stop();
spin_unlock(&wdt_lock);//释放自旋锁,即解锁
}
static void s3c2410wdt_start(void)
{
unsigned long wtcon;
spin_lock(&wdt_lock);
__s3c2410wdt_stop();
wtcon = readl(wdt_base + S3C2410_WTCON);
wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
if (soft_noboot) {
wtcon |= S3C2410_WTCON_INTEN;//该为1时,看门狗为一般定时器产生中断
wtcon &= ~S3C2410_WTCON_RSTEN;//重启无效
} else {
wtcon &= ~S3C2410_WTCON_INTEN;//默认为可复位
wtcon |= S3C2410_WTCON_RSTEN;
}
DBG("%s: wdt_count=0xx, wtcon=lx\n",__func__, wdt_count, wtcon);
writel(wdt_count, wdt_base + S3C2410_WTDAT);
writel(wdt_count, wdt_base + S3C2410_WTCNT);
writel(wtcon, wdt_base + S3C2410_WTCON);
spin_unlock(&wdt_lock);
}
//计算并设置看门狗定时器时钟周期值并初始化看门狗定时器
static int s3c2410wdt_set_heartbeat(int timeout)//timeout是默认的喂狗时间
{
unsigned int freq = clk_get_rate(wdt_clock);//clk_get_rate — obtain the current clock rate (in Hz) for a clock source. This is only valid once the clock source has been enabled.
unsigned int count;
unsigned int divisor = 1;
unsigned long wtcon;
if (timeout < 1)
return -EINVAL;
freq /= 128;
count = timeout * freq;
DBG("%s: count=%d, timeout=%d, freq=%d\n",__func__, count, timeout, freq);
if (count >= 0x10000) {
for (divisor = 1; divisor <= 0x100; divisor++) {
if ((count / divisor) < 0x10000)
break;
}
if ((count / divisor) >= 0x10000) {
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <mach/map.h>
#include <plat/regs-watchdog.h>
#define S3C_VA_WATCHDOG (0)
#define PFX "s3c2410-wdt:"
#define CONFIG_S3C2410_WATCHDOG_ATBOOT
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME
static int nowayout = WATCHDOG_NOWAYOUT;//nowayout与CONFIG_WATCHDOG_NOWAYOUT配置相关,其一旦配置应用层调用close函数将不能关闭看门狗
static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;//默认的喂狗时间
static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;//关于tmr_atboot,要想系统一上电自动使能看门狗,就为1。最好使用0,由于我们想通过open函数来打开看门狗
static int soft_noboot;//soft_noboot为1时看门狗将作为一般的中断定时器使用,为0时作为可复位电路的看门狗,默认为0
static int debug;
module_param(tmr_margin, int, 0);
module_param(tmr_atboot, int, 0);
module_param(nowayout, int, 0);
module_param(soft_noboot, int, 0);
module_param(debug, int, 0);
//下面的这些没什么大的作用,就是为了做参数描述
MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default="
MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default="
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
static unsigned long open_lock;
static struct device *wdt_dev;
//用来保存watchdog的IO端口占用的IO空间和经过虚拟映射后的内存地址
static struct resource *wdt_mem;
static void __iomem *wdt_base;
static struct resource *wdt_irq;
//保存从平台时钟队列中获取watchdog的时钟
static struct clk *wdt_clock;
//用于保存经计算后得到的计数寄存器WTCNT的计数值
static unsigned int wdt_count;
static char expect_close;
static DEFINE_SPINLOCK(wdt_lock);
#define DBG(msg...) \
do { \
} while (0) //打印调试信息
static void s3c2410wdt_keepalive(void) //喂狗
{
}
static void __s3c2410wdt_stop(void)
{
}
static void s3c2410wdt_stop(void)
{
}
static void s3c2410wdt_start(void)
{
}
//计算并设置看门狗定时器时钟周期值并初始化看门狗定时器
static int s3c2410wdt_set_heartbeat(int timeout)//timeout是默认的喂狗时间
{