歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

mini6410 看門狗源碼分析

看門狗代碼放在linux/drivers/char/watchdog/s3c2410_wdt.c中分析如下:

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