S3C2440驱动篇—看门狗驱动分析
时间:11-19
来源:互联网
点击:
Linux-2.6.32.2内核自带S3C2440看门狗驱动,只需要配置一下就可以使用。驱动源代码位于drivers/watchdog/s3c2410_wdt.c,由于驱动使用了平台设备,有关平台设备学习参考上一篇文章。
驱动实现:
#include#include #include #include #include #include #include #include #include #include interrupt.h>#include #include #include #include #undef S3C_VA_WATCHDOG#define S3C_VA_WATCHDOG (0)#include #define PFX "s3c2410-wdt: "#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)static int nowayout = WATCHDOG_NOWAYOUT;static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;static int soft_noboot;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);static unsigned long open_lock;static struct device *wdt_dev; /* platform device attached to */static struct resource *wdt_mem;static struct resource *wdt_irq;static struct clk *wdt_clock;static void __iomem *wdt_base;static unsigned int wdt_count;static char expect_close;static DEFINE_SPINLOCK(wdt_lock);/* watchdog control routines */#define DBG(msg...) do { \if (debug) \printk(KERN_INFO msg); \} while (0)/* functions */static void s3c2410wdt_keepalive(void) //喂狗{spin_lock(&wdt_lock);writel(wdt_count, wdt_base + S3C2410_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);}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;wtcon &= ~S3C2410_WTCON_RSTEN;} else {wtcon &= ~S3C2410_WTCON_INTEN;wtcon |= S3C2410_WTCON_RSTEN;}DBG("%s: wdt_count=0x%08x, wtcon=%08lx\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);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 the count is bigger than the watchdog register,then work out what we need to do (and if) we canactually make this value*/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;}}tmr_margin = timeout;DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",__func__, timeout, divisor, count, count/divisor);count /= divisor;wdt_count = count;/* update the pre-scaler */wtcon = readl(wdt_base + S3C2410_WTCON);wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);writel(count, wdt_base + S3C2410_WTDAT);writel(wtcon, wdt_base + S3C2410_WTCON);return 0;}/** /dev/watchdog handling*/static int s3c2410wdt_open(struct inode *inode, struct file *file){if (test_and_set_bit(0, &open_lock))return -EBUSY;if (nowayout) /*nowayout是内涵配置选项,如果配置则看门狗不能被关闭*/__module_get(THIS_MODULE);/*如果内核配置了CONFIG_WATCHDOG_NOWAYOUT项,则使模块使用计数加1*/expect_close = 0;/* start the timer */s3c2410wdt_start();return nonseekable_open(inode, file);/*表示返回的这个设备文件是不可以被seek操作的,nonseekable_open定义在fs.h中*/}static int s3c2410wdt_release(struct inode *inode, struct file *file){/** Shut off the timer.* Lock it in if its a module and we set nowayout*/if (expect_close == 42)s3c2410wdt_stop();else {dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");s3c2410wdt_keepalive();}expect_close = 0;clear_bit(0, &open_lock);return 0;}static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,size_t len, loff_t *ppos){/** Refresh the timer.*/if (len) {if (!nowayout) { /*如果没有配置内核CONFIG_WATCHDOG_NOWAYOUT选项,WATCHDOG_NOWAYOUT宏位于include/linux/watchdog.h*/size_t i;/* In case it was set long ago */expect_close = 0;for (i = 0; i != len; i++) {char c;if (get_user(c, data + i))return -EFAULT;if (c == V)expect_close = 42;}}/*上面的意思是想要看门狗定时器可以被关闭,则内核不要配置CONFIG_WATCHDOG_NOWAYOUT选项,对于下面这里还要“喂狗”一次,我刚开始觉得不需要,因为在看门狗
S3C2440看门狗驱 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)