mini6410 看门狗源码分析

转自: http://blog.csdn.net/muge0913/article/details/7067072
 

mini6410 看门狗源码分析


[cpp]  view plain copy print ?
  1. 看门狗代码放在linux/drivers/char/watchdog/s3c2410_wdt.c中分析如下:  
  2. 仅供技术参考,转载请注明出处:http://write.blog.csdn.net/postedit/7067072  
  3. /* linux/drivers/char/watchdog/s3c2410_wdt.c 
  4.  * 
  5.  * Copyright (c) 2004 Simtec Electronics 
  6.  *  Ben Dooks <[email protected]> 
  7.  * 
  8.  * S3C2410 Watchdog Timer Support 
  9.  * 
  10.  * Based on, softdog.c by Alan Cox, 
  11.  *     (c) Copyright 1996 Alan Cox <[email protected]> 
  12.  * 
  13.  * This program is free software; you can redistribute it and/or modify 
  14.  * it under the terms of the GNU General Public License as published by 
  15.  * the Free Software Foundation; either version 2 of the License, or 
  16.  * (at your option) any later version. 
  17.  * 
  18.  * This program is distributed in the hope that it will be useful, 
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  21.  * GNU General Public License for more details. 
  22.  * 
  23.  * You should have received a copy of the GNU General Public License 
  24.  * along with this program; if not, write to the Free Software 
  25.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  26. */  
  27.   
  28. #include <linux/module.h>  
  29. #include <linux/moduleparam.h>  
  30. #include <linux/types.h>  
  31. #include <linux/timer.h>  
  32. #include <linux/miscdevice.h>  
  33. #include <linux/watchdog.h>  
  34. #include <linux/fs.h>  
  35. #include <linux/init.h>  
  36. #include <linux/platform_device.h>  
  37. #include <linux/interrupt.h>  
  38. #include <linux/clk.h>  
  39. #include <linux/uaccess.h>  
  40. #include <linux/io.h>  
  41. #include <linux/cpufreq.h>  
  42. #include <linux/slab.h>  
  43.   
  44. #include <mach/map.h>  
  45.   
  46. #undef S3C_VA_WATCHDOG  
  47. #define S3C_VA_WATCHDOG (0)  
  48.   
  49. #include <plat/regs-watchdog.h>  
  50.   
  51. #define PFX "s3c2410-wdt: "  
  52.   
  53. #define CONFIG_S3C2410_WATCHDOG_ATBOOT      (0)  
  54. #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME    (15)  
  55. /* 
  56. *nowayout表示决不允许看门狗关闭,为1表示不允许关闭,为0表示允许关闭; 
  57. *tmr_margin表示默认的看门狗喂狗时间为15s; 
  58. *tmr_atboot表示系统启动时就使能看门狗,为1表示使能,为0表示关闭; 
  59. *soft_noboot表示看门狗工作的方式,看门狗可以作为定时器使用也可作为复位硬件使用, 
  60. *soft_noboot为1表示看门狗作为定时器使用,不发送复位信号; 
  61. *debug表示是否使用调试模式来调试代码,该模式中,会打印调试信息。 
  62. */  
  63. static int nowayout = WATCHDOG_NOWAYOUT;  
  64. static int tmr_margin   = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;  
  65. static int tmr_atboot   = CONFIG_S3C2410_WATCHDOG_ATBOOT;  
  66. static int soft_noboot;  
  67. static int debug;  
  68.   
  69. module_param(tmr_margin,  int, 0);  
  70. module_param(tmr_atboot,  int, 0);  
  71. module_param(nowayout,    int, 0);  
  72. module_param(soft_noboot, int, 0);  
  73. module_param(debug,   int, 0);  
  74.   
  75. MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default="  
  76.         __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");  
  77. MODULE_PARM_DESC(tmr_atboot,  
  78.         "Watchdog is started at boot time if set to 1, default="  
  79.             __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));  
  80. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="  
  81.             __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");  
  82. MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "  
  83.             "0 to reboot (default 0)");  
  84. MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");  
  85.   
  86. static unsigned long open_lock;  
  87. static struct device    *wdt_dev;   /* platform device attached to */  
  88. static struct resource  *wdt_mem;  
  89. static struct resource  *wdt_irq;  
  90. static struct clk   *wdt_clock;  
  91. static void __iomem *wdt_base;  
  92. static unsigned int  wdt_count;  
  93. static char      expect_close;  
  94. static DEFINE_SPINLOCK(wdt_lock);  
  95.   
  96. /* watchdog control routines */  
  97.   
  98. #define DBG(msg...) do { \  
  99.     if (debug) \  
  100.         printk(KERN_INFO msg); \  
  101.     } while (0)  
  102.   
  103. /* functions */  
  104.   
  105. static void s3c2410wdt_keepalive(void)  
  106. {  
  107.     spin_lock(&wdt_lock);  
  108.     writel(wdt_count, wdt_base + S3C2410_WTCNT);  
  109.     spin_unlock(&wdt_lock);  
  110. }  
  111.   
  112. static void __s3c2410wdt_stop(void)  
  113. {  
  114.     unsigned long wtcon;  
  115.   
  116.     wtcon = readl(wdt_base + S3C2410_WTCON);  
  117.     wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);  
  118.     writel(wtcon, wdt_base + S3C2410_WTCON);  
  119. }  
  120.   
  121. static void s3c2410wdt_stop(void)  
  122. {  
  123.     spin_lock(&wdt_lock);  
  124.     __s3c2410wdt_stop();  
  125.     spin_unlock(&wdt_lock);  
  126. }  
  127.   
  128. static void s3c2410wdt_start(void)  
  129. {  
  130.     unsigned long wtcon;  
  131.   
  132.     spin_lock(&wdt_lock);  
  133.     /*首先停止看门狗*/  
  134.     __s3c2410wdt_stop();  
  135.     /*读看门狗的控制寄存器*/  
  136.     wtcon = readl(wdt_base + S3C2410_WTCON);  
  137.     /*使能看门狗,设置时钟分频值为128*/  
  138.     wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;  
  139.     /*上边说过看门狗一个作为一个正常的16位内部定时器也可作为复位硬件*/   
  140.     if (soft_noboot) {//如果作为内部定时器   
  141.         wtcon |= S3C2410_WTCON_INTEN;//开中断使能   
  142.         wtcon &= ~S3C2410_WTCON_RSTEN;//关闭复位使能  
  143.     } else {//如果作为复位硬件  
  144.         wtcon &= ~S3C2410_WTCON_INTEN;//关闭中断使能  
  145.         wtcon |= S3C2410_WTCON_RSTEN;//开复位使能  
  146.     }  
  147.   
  148.     DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",  
  149.         __func__, wdt_count, wtcon);  
  150. /*这里为什么要设置WTCNT的值,不是WTDAT中的值自动载入WTCNT吗?看看datasheet就知道了,看门狗定时器最初 
  151. *使能的时候,WTDAT寄存器的值不会自动载入时        间计数器,所以WTCNT寄存器必须在使能它之前设置一个初始值 
  152. */    
  153.     writel(wdt_count, wdt_base + S3C2410_WTDAT);  
  154.     writel(wdt_count, wdt_base + S3C2410_WTCNT);  
  155.     writel(wtcon, wdt_base + S3C2410_WTCON);  
  156.     spin_unlock(&wdt_lock);  
  157. }  
  158.   
  159. static inline int s3c2410wdt_is_running(void)  
  160. {  
  161.     return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;  
  162. }  
  163.   
  164. static int s3c2410wdt_set_heartbeat(int timeout)  
  165. {  
  166.     /*首先获得看门狗的时钟*/  
  167.     unsigned long freq = clk_get_rate(wdt_clock);  
  168.     unsigned int count;  
  169.     unsigned int divisor = 1;  
  170.     unsigned long wtcon;  
  171.   
  172.     if (timeout < 1)  
  173.         return -EINVAL;  
  174.   
  175.     freq /= 128;  
  176.     /*秒数乘以每秒的时间滴答等于计数值*/  
  177.     count = timeout * freq;  
  178.   
  179.     DBG("%s: count=%d, timeout=%d, freq=%lu\n",  
  180.         __func__, count, timeout, freq);  
  181.   
  182.     /* if the count is bigger than the watchdog register, 
  183.        then work out what we need to do (and if) we can 
  184.        actually make this value 
  185.     */  
  186.     /*计数值不能大于WTCNT的最大范围,WTCNT是一个16位的计数器,最大值是0x10000*/  
  187.     if (count >= 0x10000) {  
  188.         for (divisor = 1; divisor <= 0x100; divisor++) {  
  189.             if ((count / divisor) < 0x10000)  
  190.                 break;  
  191.         }  
  192.         /*未找到返回错误*/  
  193.         if ((count / divisor) >= 0x10000) {  
  194.             dev_err(wdt_dev, "timeout %d too big\n", timeout);  
  195.             return -EINVAL;  
  196.         }  
  197.     }  
  198.       
  199.     /*看门狗的喂狗时间*/   
  200.     tmr_margin = timeout;  
  201.   
  202.     DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",  
  203.         __func__, timeout, divisor, count, count/divisor);  
  204.   
  205.     count /= divisor;  
  206.     wdt_count = count;  
  207.   
  208.     /* update the pre-scaler */  
  209.     //读看门狗的控制寄存器  
  210.     wtcon = readl(wdt_base + S3C2410_WTCON);  
  211.     //看门狗控制器高8位清零,也就是预分频部分清零  
  212.     wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;  
  213.     //填入预分频系数  
  214.     wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);  
  215.   
  216.     //填入计数值  
  217.     writel(count, wdt_base + S3C2410_WTDAT);  
  218.     //填入控制寄存器的值   
  219.     writel(wtcon, wdt_base + S3C2410_WTCON);  
  220.   
  221.     return 0;  
  222. }  
  223.   
  224. /* 
  225.  *  /dev/watchdog handling 
  226.  */  
  227.   
  228. static int s3c2410wdt_open(struct inode *inode, struct file *file)  
  229. {  
  230.     /*检查open_lock的第0位,如果open_lock的第0位为0,则表示test_and_set_bit的返回值为0,  
  231.         表示wdt设备没有被其他进程打开,如果为1,表示被其他进程打开,返回EBUSY*/    
  232.     if (test_and_set_bit(0, &open_lock))  
  233.         return -EBUSY;  
  234.   
  235.   
  236.     /*如果决不允许关闭看门狗,增加引用计数*/   
  237.     if (nowayout)  
  238.         __module_get(THIS_MODULE);  
  239.     /*设为不允许关闭*/  
  240.     expect_close = 0;  
  241.   
  242.     /* start the timer */  
  243.     /*开启看门狗*/  
  244.     s3c2410wdt_start();  
  245.     /*这些寄存器不需要像文件一样对位置进行寻址*/  
  246.     return nonseekable_open(inode, file);  
  247. }  
  248.   
  249. static int s3c2410wdt_release(struct inode *inode, struct file *file)  
  250. {  
  251.     /* 
  252.      *  Shut off the timer. 
  253.      *  Lock it in if it's a module and we set nowayout 
  254.      */  
  255.   
  256.     if (expect_close == 42)//看门狗为允许关闭状态  
  257.         s3c2410wdt_stop();//关闭看门狗    
  258.     else {  
  259.         dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");  
  260.         s3c2410wdt_keepalive();//否则喂狗  
  261.     }  
  262.     expect_close = 0; //设为不允许关闭   
  263.     clear_bit(0, &open_lock);//将open_lock的第0位设为0,是原子操作  
  264.     return 0;  
  265. }  
  266.   
  267. static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,  
  268.                 size_t len, loff_t *ppos)  
  269. {  
  270.     /* 
  271.      *  Refresh the timer. 
  272.      */  
  273.     if (len) {//有数据写入len不为0    
  274.         if (!nowayout) {//允许关闭   
  275.             size_t i;  
  276.   
  277.             /* In case it was set long ago */  
  278.             expect_close = 0; //关闭允许关闭状态   
  279.   
  280.             for (i = 0; i != len; i++) {  
  281.                 char c;  
  282.   
  283.                 if (get_user(c, data + i))  
  284.                     return -EFAULT;  
  285.                 if (c == 'V')//如果向设备写入'V',就允许关闭设  
  286.                     expect_close = 42;  
  287.             }  
  288.         }  
  289.         s3c2410wdt_keepalive();  
  290.     }  
  291.     return len;  
  292. }  
  293.   
  294. #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)  
  295.   
  296. static const struct watchdog_info s3c2410_wdt_ident = {  
  297.     .options          =     OPTIONS,  
  298.     .firmware_version = 0,  
  299.     .identity         = "S3C2410 Watchdog",  
  300. };  
  301.   
  302.   
  303. static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd,  
  304.                             unsigned long arg)  
  305. {  
  306.     void __user *argp = (void __user *)arg;  
  307.     int __user *p = argp;  
  308.     int new_margin;  
  309.   
  310.     switch (cmd) {  
  311.     case WDIOC_GETSUPPORT://获得看门狗设备的信息   
  312.         return copy_to_user(argp, &s3c2410_wdt_ident,  
  313.             sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;  
  314.     case WDIOC_GETSTATUS:  
  315.     case WDIOC_GETBOOTSTATUS:  
  316.         return put_user(0, p);  
  317.     case WDIOC_KEEPALIVE://对看门狗进行喂狗  
  318.         s3c2410wdt_keepalive();  
  319.         return 0;  
  320.     case WDIOC_SETTIMEOUT://设置看门狗的超时时间  
  321.         if (get_user(new_margin, p))  
  322.             return -EFAULT;  
  323.         if (s3c2410wdt_set_heartbeat(new_margin))  
  324.             return -EINVAL;  
  325.         s3c2410wdt_keepalive();  
  326.         return put_user(tmr_margin, p);  
  327.     case WDIOC_GETTIMEOUT:  
  328.         return put_user(tmr_margin, p);  
  329.     default:  
  330.         return -ENOTTY;  
  331.     }  
  332. }  
  333.   
  334. /* kernel interface */  
  335. /* 
  336. *看门狗驱动作为字符驱动的file_operations结构 
  337. */  
  338. static const struct file_operations s3c2410wdt_fops = {  
  339.     .owner      = THIS_MODULE,  
  340.     .llseek     = no_llseek,  
  341.     .write      = s3c2410wdt_write,  
  342.     .unlocked_ioctl = s3c2410wdt_ioctl,  
  343.     .open       = s3c2410wdt_open,  
  344.     .release    = s3c2410wdt_release,  
  345. };  
  346.   
  347. static struct miscdevice s3c2410wdt_miscdev = {  
  348.     .minor      = WATCHDOG_MINOR,  
  349.     .name       = "watchdog",  
  350.     .fops       = &s3c2410wdt_fops,  
  351. };  
  352.   
  353. /* interrupt handler code */  
  354. /* 
  355. *如果选择了看门狗作为内部定时器,则当计数值为0时调用中断处理函数,中断处理函数的主要功能就是喂狗 
  356. */  
  357. static irqreturn_t s3c2410wdt_irq(int irqno, void *param)  
  358. {  
  359.     dev_info(wdt_dev, "watchdog timer expired (irq)\n");  
  360.     /*中断处理中调用喂狗*/  
  361.     s3c2410wdt_keepalive();  
  362.     return IRQ_HANDLED;  
  363. }  
  364.   
  365.   
  366. #ifdef CONFIG_CPU_FREQ  
  367.   
  368. static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,  
  369.                       unsigned long val, void *data)  
  370. {  
  371.     int ret;  
  372.   
  373.     if (!s3c2410wdt_is_running())  
  374.         goto done;  
  375.   
  376.     if (val == CPUFREQ_PRECHANGE) {  
  377.         /* To ensure that over the change we don't cause the 
  378.          * watchdog to trigger, we perform an keep-alive if 
  379.          * the watchdog is running. 
  380.          */  
  381.   
  382.         s3c2410wdt_keepalive();  
  383.     } else if (val == CPUFREQ_POSTCHANGE) {  
  384.         s3c2410wdt_stop();  
  385.   
  386.         ret = s3c2410wdt_set_heartbeat(tmr_margin);  
  387.   
  388.         if (ret >= 0)  
  389.             s3c2410wdt_start();  
  390.         else  
  391.             goto err;  
  392.     }  
  393.   
  394. done:  
  395.     return 0;  
  396.   
  397.  err:  
  398.     dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin);  
  399.     return ret;  
  400. }  
  401.   
  402. static struct notifier_block s3c2410wdt_cpufreq_transition_nb = {  
  403.     .notifier_call  = s3c2410wdt_cpufreq_transition,  
  404. };  
  405.   
  406. static inline int s3c2410wdt_cpufreq_register(void)  
  407. {  
  408.     return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb,  
  409.                      CPUFREQ_TRANSITION_NOTIFIER);  
  410. }  
  411.   
  412. static inline void s3c2410wdt_cpufreq_deregister(void)  
  413. {  
  414.     cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb,  
  415.                     CPUFREQ_TRANSITION_NOTIFIER);  
  416. }  
  417.   
  418. #else  
  419. static inline int s3c2410wdt_cpufreq_register(void)  
  420. {  
  421.     return 0;  
  422. }  
  423.   
  424. static inline void s3c2410wdt_cpufreq_deregister(void)  
  425. {  
  426. }  
  427. #endif  
  428.   
  429.   
  430.   
  431. /* device interface */  
  432.   
  433. static int __devinit s3c2410wdt_probe(struct platform_device *pdev)  
  434. {  
  435.     struct resource *res;  
  436.     struct device *dev;  
  437.     unsigned int wtcon;  
  438.     int started = 0;  
  439.     int ret;  
  440.     int size;  
  441.   
  442.     DBG("%s: probe=%p\n", __func__, pdev);  
  443.     /*平台设备中的设备结构体device*/  
  444.     dev = &pdev->dev;  
  445.     wdt_dev = &pdev->dev;  
  446.   
  447.     /* get the memory region for the watchdog timer */  
  448.      /*获得看门狗的内存资源*/  
  449.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  450.     /*获取失败则推出*/  
  451.     if (res == NULL) {  
  452.         dev_err(dev, "no memory resource specified\n");  
  453.         return -ENOENT;  
  454.     }  
  455.     /*内存资源所占的字节数*/  
  456.     size = resource_size(res);  
  457.     /*申请一块IO内存,对应看门狗的3个寄存器*/  
  458.     wdt_mem = request_mem_region(res->start, size, pdev->name);  
  459.     if (wdt_mem == NULL) {  
  460.         dev_err(dev, "failed to get memory region\n");  
  461.         return -EBUSY;  
  462.     }  
  463.     /*获得虚拟地址*/   
  464.     wdt_base = ioremap(res->start, size);  
  465.     if (wdt_base == NULL) {  
  466.         dev_err(dev, "failed to ioremap() region\n");  
  467.         ret = -EINVAL;  
  468.         goto err_req;  
  469.     }  
  470.   
  471.     DBG("probe: mapped wdt_base=%p\n", wdt_base);  
  472.     /*申请中断*/  
  473.     wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  
  474.     if (wdt_irq == NULL) {  
  475.         dev_err(dev, "no irq resource specified\n");  
  476.         ret = -ENOENT;  
  477.         goto err_map;  
  478.     }  
  479.       
  480.     /*并注册中断处理函数*/  
  481.     ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);  
  482.     if (ret != 0) {  
  483.         dev_err(dev, "failed to install irq (%d)\n", ret);  
  484.         goto err_map;  
  485.     }  
  486.     /*获得看门狗时钟*/   
  487.     wdt_clock = clk_get(&pdev->dev, "watchdog");  
  488.     if (IS_ERR(wdt_clock)) {  
  489.         dev_err(dev, "failed to find watchdog clock source\n");  
  490.         ret = PTR_ERR(wdt_clock);  
  491.         goto err_irq;  
  492.     }  
  493.     /*时钟使能*/   
  494.     clk_enable(wdt_clock);  
  495.   
  496.     if (s3c2410wdt_cpufreq_register() < 0) {  
  497.         printk(KERN_ERR PFX "failed to register cpufreq\n");  
  498.         goto err_clk;  
  499.     }  
  500.   
  501.     /* see if we can actually set the requested timer margin, and if 
  502.      * not, try the default value */  
  503.     /*设置看门狗复位时间,如果成功返回0*/  
  504.     if (s3c2410wdt_set_heartbeat(tmr_margin)) {  
  505.         /*如果不成功,看门狗的复位时间设置成默认值*/  
  506.         started = s3c2410wdt_set_heartbeat(  
  507.                     CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);  
  508.   
  509.         if (started == 0)  
  510.             dev_info(dev,  
  511.                "tmr_margin value out of range, default %d used\n",  
  512.                    CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);  
  513.         else  
  514.             dev_info(dev, "default timer value is out of range, "  
  515.                             "cannot start\n");  
  516.     }  
  517.     /*注册混杂设备*/  
  518.     ret = misc_register(&s3c2410wdt_miscdev);  
  519.     if (ret) {  
  520.         dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",  
  521.             WATCHDOG_MINOR, ret);  
  522.         goto err_cpufreq;  
  523.     }  
  524.     /*如果开机的时候就启动看门狗*/  
  525.     if (tmr_atboot && started == 0) {  
  526.         dev_info(dev, "starting watchdog timer\n");  
  527.         s3c2410wdt_start();//启动看门狗   
  528.     } else if (!tmr_atboot) {  
  529.         /* if we're not enabling the watchdog, then ensure it is 
  530.          * disabled if it has been left running from the bootloader 
  531.          * or other source */  
  532.   
  533.         s3c2410wdt_stop();//关闭看门狗  
  534.     }  
  535.   
  536.     /* print out a statement of readiness */  
  537.     /*读出看门狗控制寄存器的值*/  
  538.     wtcon = readl(wdt_base + S3C2410_WTCON);  
  539.     /*打印看门狗是否使能,是否允许发出复位信号,是否允许发出中断信号*/   
  540.     dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",  
  541.          (wtcon & S3C2410_WTCON_ENABLE) ?  "" : "in",  
  542.          (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis",  
  543.          (wtcon & S3C2410_WTCON_INTEN) ? "" : "en");  
  544.   
  545.     return 0;  
  546.   
  547.  err_cpufreq:  
  548.     s3c2410wdt_cpufreq_deregister();  
  549.   
  550.  err_clk:  
  551.     clk_disable(wdt_clock);  
  552.     clk_put(wdt_clock);  
  553.   
  554.  err_irq:  
  555.     free_irq(wdt_irq->start, pdev);  
  556.   
  557.  err_map:  
  558.     iounmap(wdt_base);  
  559.   
  560.  err_req:  
  561.     release_resource(wdt_mem);  
  562.     kfree(wdt_mem);  
  563.   
  564.     return ret;  
  565. }  
  566.   
  567. static int __devexit s3c2410wdt_remove(struct platform_device *dev)  
  568. {  
  569.     misc_deregister(&s3c2410wdt_miscdev);//注销混杂设备  
  570.   
  571.     s3c2410wdt_cpufreq_deregister();  
  572.   
  573.     clk_disable(wdt_clock);//关闭时钟  
  574.     clk_put(wdt_clock);//减少时钟引用计数  
  575.     wdt_clock = NULL;  
  576.   
  577.     free_irq(wdt_irq->start, dev);//释放中断号  
  578.     wdt_irq = NULL;  
  579.   
  580.     iounmap(wdt_base);//关闭内存映射  
  581.   
  582.     release_resource(wdt_mem);//释放平台资源  
  583.     kfree(wdt_mem);//释放I/O内存  
  584.     wdt_mem = NULL;  
  585.     return 0;  
  586. }  
  587.   
  588. static void s3c2410wdt_shutdown(struct platform_device *dev)  
  589. {  
  590.     s3c2410wdt_stop();  
  591. }  
  592.   
  593. #ifdef CONFIG_PM  
  594.   
  595. static unsigned long wtcon_save;  
  596. static unsigned long wtdat_save;  
  597. /* 
  598. *平台驱动中的电源管理部分 
  599. */  
  600. static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)  
  601. {  
  602.     /* Save watchdog state, and turn it off. */  
  603.     /*只要保存S3C2410_WTDAT就可以了,不需要保存S3C2410_WTCNT, 
  604.     *S3C2410_WTCNT的值会在系统还原的时候直接赋为S3C2410_WTDAT中的值 
  605.     */   
  606.     wtcon_save = readl(wdt_base + S3C2410_WTCON);  
  607.     wtdat_save = readl(wdt_base + S3C2410_WTDAT);  
  608.   
  609.     /* Note that WTCNT doesn't need to be saved. */  
  610.     s3c2410wdt_stop();  
  611.   
  612.     return 0;  
  613. }  
  614.   
  615. static int s3c2410wdt_resume(struct platform_device *dev)  
  616. {  
  617.     /* Restore watchdog state. */  
  618.   
  619.     writel(wtdat_save, wdt_base + S3C2410_WTDAT);  
  620.     writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */  
  621.     writel(wtcon_save, wdt_base + S3C2410_WTCON);  
  622.   
  623.     printk(KERN_INFO PFX "watchdog %sabled\n",  
  624.            (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");  
  625.   
  626.     return 0;  
  627. }  
  628.   
  629. #else  
  630. #define s3c2410wdt_suspend NULL  
  631. #define s3c2410wdt_resume  NULL  
  632. #endif /* CONFIG_PM */  
  633.   
  634. /* 
  635. *S3C2410的看门狗同时具有多重身份:字符设备,混杂设备,平台设备。 
  636. *下面是看门狗驱动作为平台驱动的描述: 
  637. */  
  638. static struct platform_driver s3c2410wdt_driver = {  
  639.     .probe      = s3c2410wdt_probe,  
  640.     .remove     = __devexit_p(s3c2410wdt_remove),  
  641.     .shutdown   = s3c2410wdt_shutdown,  
  642.     .suspend    = s3c2410wdt_suspend,  
  643.     .resume     = s3c2410wdt_resume,  
  644.     .driver     = {  
  645.         .owner  = THIS_MODULE,  
  646.         .name   = "s3c2410-wdt",  
  647.     },  
  648. };  
  649.   
  650.   
  651. static char banner[] __initdata =  
  652.     KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";  
  653.   
  654.   
  655. /* 
  656. *看门狗驱动作为平台驱动的注册 
  657. */  
  658. static int __init watchdog_init(void)  
  659. {  
  660.     printk(banner);  
  661.     return platform_driver_register(&s3c2410wdt_driver);  
  662. }  
  663.   
  664. static void __exit watchdog_exit(void)  
  665. {  
  666.     platform_driver_unregister(&s3c2410wdt_driver);  
  667. }  
  668.   
  669. module_init(watchdog_init);  
  670. module_exit(watchdog_exit);  
  671.   
  672. MODULE_AUTHOR("Ben Dooks <[email protected]>, "  
  673.           "Dimitry Andric <[email protected]>");  
  674. MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");  
  675. MODULE_LICENSE("GPL");  
  676. MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);  
  677. MODULE_ALIAS("platform:s3c2410-wdt");  

你可能感兴趣的:(mini6410 看门狗源码分析)