rk29: add watch dog driver
authorhhb <hhb@rock-chips.com>
Tue, 5 Jul 2011 12:46:18 +0000 (20:46 +0800)
committerhhb <hhb@rock-chips.com>
Tue, 5 Jul 2011 12:57:31 +0000 (20:57 +0800)
arch/arm/mach-rk29/board-rk29-ddr3sdk.c
arch/arm/mach-rk29/board-rk29-phonesdk.c [changed mode: 0755->0644]
arch/arm/mach-rk29/board-rk29phonepadsdk.c
arch/arm/mach-rk29/board-rk29sdk.c
arch/arm/mach-rk29/devices.c [changed mode: 0755->0644]
arch/arm/mach-rk29/devices.h [changed mode: 0755->0644]
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/rk29_wdt.c [new file with mode: 0644]

index c916b0ba7a8b938cf3b1eba020fd3ca1144f5894..4fb9faf0dbd3739dbc009f393a9798eb2a76ab6c 100755 (executable)
@@ -1318,6 +1318,11 @@ static void __init rk29_board_iomux_init(void)
 }
 
 static struct platform_device *devices[] __initdata = {
+
+#ifdef CONFIG_RK29_WATCHDOG
+       &rk29_device_wdt,
+#endif
+
 #ifdef CONFIG_UART1_RK29
        &rk29_device_uart1,
 #endif
old mode 100755 (executable)
new mode 100644 (file)
index 256664c..ea480af
@@ -2557,6 +2557,11 @@ static void __init rk29_board_iomux_init(void)
 }
 
 static struct platform_device *devices[] __initdata = {
+
+#ifdef CONFIG_RK29_WATCHDOG
+       &rk29_device_wdt,
+#endif
+
 #ifdef CONFIG_UART1_RK29
        &rk29_device_uart1,
 #endif
index df490af41c5e3a98c051ad67d2968c40cf57e6c7..63eb59c91973beb0e55951a7b10b11481b6cd730 100644 (file)
@@ -1374,6 +1374,11 @@ static void __init rk29_board_iomux_init(void)
 }
 
 static struct platform_device *devices[] __initdata = {
+
+#ifdef CONFIG_RK29_WATCHDOG
+       &rk29_device_wdt,
+#endif
+
 #ifdef CONFIG_UART1_RK29
        &rk29_device_uart1,
 #endif
index 5cb5c67cfd2afa601ac27ed66f234f3165d39c11..a9867898e0ccc177f7a1e93526406ecd31be2480 100755 (executable)
@@ -1323,6 +1323,11 @@ static void __init rk29_board_iomux_init(void)
 }
 
 static struct platform_device *devices[] __initdata = {
+
+#ifdef CONFIG_RK29_WATCHDOG
+       &rk29_device_wdt,
+#endif
+
 #ifdef CONFIG_UART1_RK29
        &rk29_device_uart1,
 #endif
old mode 100755 (executable)
new mode 100644 (file)
index 5e67889..364079e
@@ -283,6 +283,36 @@ struct platform_device rk29_device_sdmmc1 = {
        },
 };
 #endif
+
+/*
+ * rk29 wdt device  ADDED BY HHB@ROCK-CHIPS.COM
+ */
+
+#ifdef CONFIG_RK29_WATCHDOG
+
+static struct resource resources_wdt[] = {
+       {
+               .start  = IRQ_WDT,
+               .end    = IRQ_WDT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK29_WDT_PHYS,
+               .end    = RK29_WDT_PHYS + RK29_WDT_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device rk29_device_wdt = {
+       .name   = "rk29-wdt",
+       .id     = 0,
+       .num_resources  = ARRAY_SIZE(resources_wdt),
+       .resource       = resources_wdt,
+};
+
+#endif
+
+
 /*
  * rk29 4 uarts device
  */
old mode 100755 (executable)
new mode 100644 (file)
index 8cf367d..9c95ab3
@@ -76,4 +76,6 @@ extern struct platform_device rk29_device_rndis;
 extern struct platform_device rk29_device_vmac;
 extern struct rk29_vmac_platform_data rk29_vmac_pdata;
 extern struct platform_device rk29_device_ipp;
+extern struct platform_device rk29_device_wdt;
+
 #endif
index 3711b888d482f13f2284d5c25c16a9d84d1ecbab..8c510336896a979b396cd5410bb30c14f2b78b56 100644 (file)
@@ -73,6 +73,32 @@ config WM8350_WATCHDOG
 
 # ARM Architecture
 
+config RK29_WATCHDOG
+       tristate "RK29 watchdog"
+       depends on ARCH_RK29
+       help
+         Watchdog timer embedded into RK29xx chips. This will reboot your
+         system when the timeout is reached.
+
+config RK29_FEED_DOG_BY_INTE
+       bool "feed watchdog by interrupt"
+       depends on RK29_WATCHDOG
+
+config RK29_WATCHDOG_ATBOOT
+       bool "start watchdog at system boot"
+       depends on RK29_WATCHDOG
+
+config RK29_WATCHDOG_DEFAULT_TIME
+       int "set watchdog time out value (unit second)"
+       depends on RK29_WATCHDOG
+       help
+         the real time out value is two times more than the setting value
+
+config RK29_WATCHDOG_DEBUG
+       bool "enable watchdog debug"
+       depends on RK29_WATCHDOG
+
+
 config AT91RM9200_WATCHDOG
        tristate "AT91RM9200 watchdog"
        depends on ARCH_AT91RM9200
index 699199b1baa6baf24d31f8e0355631ab84b1060d..b4de466ace6f33ff38b4df92721b118d37d694ea 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
 obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
 obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o
+obj-$(CONFIG_RK29_WATCHDOG) += rk29_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/rk29_wdt.c b/drivers/watchdog/rk29_wdt.c
new file mode 100644 (file)
index 0000000..c155bdb
--- /dev/null
@@ -0,0 +1,510 @@
+/* linux/drivers/watchdog/rk29_wdt.c\r
+ *\r
+ * Copyright (C) 2011 ROCKCHIP, Inc.\r
+ *     hhb@rock-chips.com\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+\r
+#include <linux/module.h>\r
+#include <linux/moduleparam.h>\r
+#include <linux/types.h>\r
+#include <linux/timer.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/watchdog.h>\r
+#include <linux/fs.h>\r
+#include <linux/init.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/clk.h>\r
+#include <linux/uaccess.h>\r
+#include <linux/io.h>\r
+\r
+#include <asm/mach/map.h>\r
+\r
+\r
+/* RK29 registers define */\r
+#define RK29_WDT_CR    0X00\r
+#define RK29_WDT_TORR  0X04\r
+#define RK29_WDT_CCVR  0X08\r
+#define RK29_WDT_CRR   0X0C\r
+#define RK29_WDT_STAT  0X10\r
+#define RK29_WDT_EOI   0X14\r
+\r
+#define RK29_WDT_EN     1\r
+#define RK29_RESPONSE_MODE     1\r
+#define RK29_RESET_PULSE    4\r
+\r
+//THAT wdt's clock is 24MHZ\r
+#define RK29_WDT_2730US        0\r
+#define RK29_WDT_5460US        1\r
+#define RK29_WDT_10920US       2\r
+#define RK29_WDT_21840US       3\r
+#define RK29_WDT_43680US       4\r
+#define RK29_WDT_87360US       5\r
+#define RK29_WDT_174720US      6\r
+#define RK29_WDT_349440US      7\r
+#define RK29_WDT_698880US      8\r
+#define RK29_WDT_1397760US     9\r
+#define RK29_WDT_2795520US     10\r
+#define RK29_WDT_5591040US     11\r
+#define RK29_WDT_11182080US    12\r
+#define RK29_WDT_22364160US    13\r
+#define RK29_WDT_44728320US    14\r
+#define RK29_WDT_89456640US    15\r
+\r
+/*\r
+#define CONFIG_RK29_WATCHDOG_ATBOOT            (1)\r
+#define CONFIG_RK29_WATCHDOG_DEFAULT_TIME      10      //unit second\r
+#define CONFIG_RK29_WATCHDOG_DEBUG     1\r
+*/\r
+\r
+static int nowayout    = WATCHDOG_NOWAYOUT;\r
+static int tmr_margin  = CONFIG_RK29_WATCHDOG_DEFAULT_TIME;\r
+#ifdef CONFIG_RK29_WATCHDOG_ATBOOT\r
+static int tmr_atboot  = 1;\r
+#else\r
+static int tmr_atboot  = 0;\r
+#endif\r
+\r
+static int soft_noboot;\r
+\r
+#ifdef CONFIG_RK29_WATCHDOG_DEBUG\r
+static int debug       = 1;\r
+#else\r
+static int debug       = 0;\r
+#endif\r
+\r
+module_param(tmr_margin,  int, 0);\r
+module_param(tmr_atboot,  int, 0);\r
+module_param(nowayout,    int, 0);\r
+module_param(soft_noboot, int, 0);\r
+module_param(debug,      int, 0);\r
+\r
+MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default="\r
+               __MODULE_STRING(CONFIG_RK29_WATCHDOG_DEFAULT_TIME) ")");\r
+MODULE_PARM_DESC(tmr_atboot,\r
+               "Watchdog is started at boot time if set to 1, default="\r
+                       __MODULE_STRING(CONFIG_RK29_WATCHDOG_ATBOOT));\r
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="\r
+                       __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");\r
+MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "\r
+                       "0 to reboot (default depends on ONLY_TESTING)");\r
+MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");\r
+\r
+\r
+static unsigned long open_lock;\r
+static struct device    *wdt_dev;      /* platform device attached to */\r
+static struct resource *wdt_mem;\r
+static struct resource *wdt_irq;\r
+static struct clk      *wdt_clock;\r
+static void __iomem    *wdt_base;\r
+static unsigned int     wdt_count;\r
+static char             expect_close;\r
+\r
+static DEFINE_SPINLOCK(wdt_lock);\r
+\r
+/* watchdog control routines */\r
+\r
+#define DBG(msg...) do { \\r
+       if (debug) \\r
+               printk(KERN_INFO msg); \\r
+       } while (0)\r
+\r
+\r
+/* functions */\r
+static void rk29_wdt_keepalive(void)\r
+{\r
+       spin_lock(&wdt_lock);\r
+       writel(0x76, wdt_base + RK29_WDT_CRR);\r
+       spin_unlock(&wdt_lock);\r
+}\r
+\r
+static void __rk29_wdt_stop(void)\r
+{\r
+       unsigned long wtcon = 0;\r
+\r
+       wtcon = readl(wdt_base + RK29_WDT_CR);\r
+       wtcon &= 0xfffffffe;\r
+       writel(wtcon, wdt_base + RK29_WDT_CR);\r
+}\r
+\r
+static void rk29_wdt_stop(void)\r
+{\r
+       spin_lock(&wdt_lock);\r
+       __rk29_wdt_stop();\r
+       spin_unlock(&wdt_lock);\r
+}\r
+\r
+static void rk29_wdt_start(void)\r
+{\r
+       unsigned long wtcon = 0;\r
+\r
+       spin_lock(&wdt_lock);\r
+       __rk29_wdt_stop();\r
+       wtcon |= (RK29_WDT_EN << 0) | (RK29_RESPONSE_MODE << 1) | (RK29_RESET_PULSE << 2);\r
+       writel(wtcon, wdt_base + RK29_WDT_CR);\r
+       spin_unlock(&wdt_lock);\r
+}\r
+/* timeout unit us */\r
+static int rk29_wdt_set_heartbeat(int timeout)\r
+{\r
+       unsigned int freq = clk_get_rate(wdt_clock);\r
+       unsigned int count;\r
+       unsigned int torr = 0;\r
+       unsigned int acc = 1;\r
+\r
+       if (timeout < 1)\r
+               return -EINVAL;\r
+\r
+//     freq /= 1000000;\r
+       count = timeout * freq;\r
+       count /= 0x10000;\r
+\r
+       while(acc < count){\r
+               acc *= 2;\r
+               torr++;\r
+       }\r
+       if(torr > 15){\r
+               torr = 15;\r
+       }\r
+       DBG("%s:%d\n", __func__, torr);\r
+       writel(torr, wdt_base + RK29_WDT_TORR);\r
+       return 0;\r
+}\r
+\r
+/*\r
+ *     /dev/watchdog handling\r
+ */\r
+\r
+static int rk29_wdt_open(struct inode *inode, struct file *file)\r
+{\r
+       DBG("%s\n", __func__);\r
+       if (test_and_set_bit(0, &open_lock))\r
+               return -EBUSY;\r
+\r
+       if (nowayout)\r
+               __module_get(THIS_MODULE);\r
+\r
+       expect_close = 0;\r
+\r
+       /* start the timer */\r
+       rk29_wdt_start();\r
+       return nonseekable_open(inode, file);\r
+}\r
+\r
+static int rk29_wdt_release(struct inode *inode, struct file *file)\r
+{\r
+       /*\r
+        *      Shut off the timer.\r
+        *      Lock it in if it's a module and we set nowayout\r
+        */\r
+       DBG("%s\n", __func__);\r
+       if (expect_close == 42)\r
+               rk29_wdt_stop();\r
+       else {\r
+               dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");\r
+               rk29_wdt_keepalive();\r
+       }\r
+       expect_close = 0;\r
+       clear_bit(0, &open_lock);\r
+       return 0;\r
+}\r
+\r
+static ssize_t rk29_wdt_write(struct file *file, const char __user *data,\r
+                               size_t len, loff_t *ppos)\r
+{\r
+       /*\r
+        *      Refresh the timer.\r
+        */\r
+       DBG("%s\n", __func__);\r
+       if (len) {\r
+               if (!nowayout) {\r
+                       size_t i;\r
+\r
+                       /* In case it was set long ago */\r
+                       expect_close = 0;\r
+\r
+                       for (i = 0; i != len; i++) {\r
+                               char c;\r
+\r
+                               if (get_user(c, data + i))\r
+                                       return -EFAULT;\r
+                               if (c == 'V')\r
+                                       expect_close = 42;\r
+                       }\r
+               }\r
+               rk29_wdt_keepalive();\r
+       }\r
+       return len;\r
+}\r
+\r
+#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)\r
+\r
+static const struct watchdog_info rk29_wdt_ident = {\r
+       .options          =     OPTIONS,\r
+       .firmware_version =     0,\r
+       .identity         =     "rk29 Watchdog",\r
+};\r
+\r
+\r
+static long rk29_wdt_ioctl(struct file *file,  unsigned int cmd,\r
+                                                       unsigned long arg)\r
+{\r
+       void __user *argp = (void __user *)arg;\r
+       int __user *p = argp;\r
+       int new_margin;\r
+       DBG("%s\n", __func__);\r
+       switch (cmd) {\r
+       case WDIOC_GETSUPPORT:\r
+               return copy_to_user(argp, &rk29_wdt_ident,\r
+                       sizeof(rk29_wdt_ident)) ? -EFAULT : 0;\r
+       case WDIOC_GETSTATUS:\r
+       case WDIOC_GETBOOTSTATUS:\r
+               return put_user(0, p);\r
+       case WDIOC_KEEPALIVE:\r
+               DBG("%s:rk29_wdt_keepalive\n", __func__);\r
+               rk29_wdt_keepalive();\r
+               return 0;\r
+       case WDIOC_SETTIMEOUT:\r
+               if (get_user(new_margin, p))\r
+                       return -EFAULT;\r
+               if (rk29_wdt_set_heartbeat(new_margin))\r
+                       return -EINVAL;\r
+               rk29_wdt_keepalive();\r
+               return put_user(tmr_margin, p);\r
+       case WDIOC_GETTIMEOUT:\r
+               return put_user(tmr_margin, p);\r
+       default:\r
+               return -ENOTTY;\r
+       }\r
+}\r
+\r
+\r
+\r
+/* kernel interface */\r
+\r
+static const struct file_operations rk29_wdt_fops = {\r
+       .owner          = THIS_MODULE,\r
+       .llseek         = no_llseek,\r
+       .write          = rk29_wdt_write,\r
+       .unlocked_ioctl = rk29_wdt_ioctl,\r
+       .open           = rk29_wdt_open,\r
+       .release        = rk29_wdt_release,\r
+};\r
+\r
+static struct miscdevice rk29_wdt_miscdev = {\r
+       .minor          = WATCHDOG_MINOR,\r
+       .name           = "watchdog",\r
+       .fops           = &rk29_wdt_fops,\r
+};\r
+\r
+\r
+/* interrupt handler code */\r
+\r
+static irqreturn_t rk29_wdt_irq_handler(int irqno, void *param)\r
+{\r
+       DBG("RK29_wdt:watchdog timer expired (irq)\n");\r
+       rk29_wdt_keepalive();\r
+       return IRQ_HANDLED;\r
+}\r
+\r
+\r
+/* device interface */\r
+\r
+static int __devinit rk29_wdt_probe(struct platform_device *pdev)\r
+{\r
+       struct resource *res;\r
+       struct device *dev;\r
+       int started = 0;\r
+       int ret;\r
+       int size;\r
+\r
+       dev = &pdev->dev;\r
+       wdt_dev = &pdev->dev;\r
+\r
+       /* get the memory region for the watchdog timer */\r
+\r
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
+       if (res == NULL) {\r
+               dev_err(dev, "no memory resource specified\n");\r
+               return -ENOENT;\r
+       }\r
+\r
+       size = (res->end - res->start) + 1;\r
+       wdt_mem = request_mem_region(res->start, size, pdev->name);\r
+       if (wdt_mem == NULL) {\r
+               dev_err(dev, "failed to get memory region\n");\r
+               ret = -ENOENT;\r
+               goto err_req;\r
+       }\r
+\r
+       wdt_base = ioremap(res->start, size);\r
+       if (wdt_base == NULL) {\r
+               dev_err(dev, "failed to ioremap() region\n");\r
+               ret = -EINVAL;\r
+               goto err_req;\r
+       }\r
+\r
+       DBG("probe: mapped wdt_base=%p\n", wdt_base);\r
+\r
+\r
+#ifdef CONFIG_RK29_FEED_DOG_BY_INTE\r
+\r
+       wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);\r
+       if (wdt_irq == NULL) {\r
+               dev_err(dev, "no irq resource specified\n");\r
+               ret = -ENOENT;\r
+               goto err_map;\r
+       }\r
+\r
+       ret = request_irq(wdt_irq->start, rk29_wdt_irq_handler, 0, pdev->name, pdev);\r
+\r
+       if (ret != 0) {\r
+               dev_err(dev, "failed to install irq (%d)\n", ret);\r
+               goto err_map;\r
+       }\r
+\r
+#endif\r
+\r
+       wdt_clock = clk_get(&pdev->dev, "wdt");\r
+       if (IS_ERR(wdt_clock)) {\r
+               dev_err(dev, "failed to find watchdog clock source\n");\r
+               ret = PTR_ERR(wdt_clock);\r
+               goto err_irq;\r
+       }\r
+\r
+       clk_enable(wdt_clock);\r
+\r
+       rk29_wdt_set_heartbeat(tmr_margin);\r
+\r
+       ret = misc_register(&rk29_wdt_miscdev);\r
+       if (ret) {\r
+               dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",\r
+                       WATCHDOG_MINOR, ret);\r
+               goto err_clk;\r
+       }\r
+       printk("watchdog misc directory:%s\n", rk29_wdt_miscdev.nodename);\r
+       if (tmr_atboot && started == 0) {\r
+               dev_info(dev, "starting watchdog timer\n");\r
+               rk29_wdt_start();\r
+       } else if (!tmr_atboot) {\r
+               /* if we're not enabling the watchdog, then ensure it is\r
+                * disabled if it has been left running from the bootloader\r
+                * or other source */\r
+\r
+               rk29_wdt_stop();\r
+       }\r
+\r
+       return 0;\r
+\r
+ err_clk:\r
+       clk_disable(wdt_clock);\r
+       clk_put(wdt_clock);\r
+\r
+ err_irq:\r
+       free_irq(wdt_irq->start, pdev);\r
+\r
+ err_map:\r
+       iounmap(wdt_base);\r
+\r
+ err_req:\r
+       release_resource(wdt_mem);\r
+       kfree(wdt_mem);\r
+\r
+       return ret;\r
+}\r
+\r
+static int __devexit rk29_wdt_remove(struct platform_device *dev)\r
+{\r
+       release_resource(wdt_mem);\r
+       kfree(wdt_mem);\r
+       wdt_mem = NULL;\r
+\r
+       free_irq(wdt_irq->start, dev);\r
+       wdt_irq = NULL;\r
+\r
+       clk_disable(wdt_clock);\r
+       clk_put(wdt_clock);\r
+       wdt_clock = NULL;\r
+\r
+       iounmap(wdt_base);\r
+       misc_deregister(&rk29_wdt_miscdev);\r
+\r
+       return 0;\r
+}\r
+\r
+static void rk29_wdt_shutdown(struct platform_device *dev)\r
+{\r
+       rk29_wdt_stop();\r
+}\r
+\r
+#ifdef CONFIG_PM\r
+\r
+static int rk29_wdt_suspend(struct platform_device *dev, pm_message_t state)\r
+{\r
+       rk29_wdt_stop();\r
+       return 0;\r
+}\r
+\r
+static int rk29_wdt_resume(struct platform_device *dev)\r
+{\r
+       rk29_wdt_set_heartbeat(tmr_margin);\r
+       rk29_wdt_start();\r
+       return 0;\r
+}\r
+\r
+#else\r
+#define rk29_wdt_suspend NULL\r
+#define rk29_wdt_resume  NULL\r
+#endif /* CONFIG_PM */\r
+\r
+\r
+static struct platform_driver rk29_wdt_driver = {\r
+       .probe          = rk29_wdt_probe,\r
+       .remove         = __devexit_p(rk29_wdt_remove),\r
+       .shutdown       = rk29_wdt_shutdown,\r
+       .suspend        = rk29_wdt_suspend,\r
+       .resume         = rk29_wdt_resume,\r
+       .driver         = {\r
+               .owner  = THIS_MODULE,\r
+               .name   = "rk29-wdt",\r
+       },\r
+};\r
+\r
+\r
+static char banner[] __initdata =\r
+       KERN_INFO "RK29 Watchdog Timer, (c) 2011 Rockchip Electronics\n";\r
+\r
+static int __init watchdog_init(void)\r
+{\r
+       printk(banner);\r
+       return platform_driver_register(&rk29_wdt_driver);\r
+}\r
+\r
+static void __exit watchdog_exit(void)\r
+{\r
+       platform_driver_unregister(&rk29_wdt_driver);\r
+}\r
+\r
+module_init(watchdog_init);\r
+module_exit(watchdog_exit);\r
+\r
+MODULE_AUTHOR("hhb@rock-chips.com");\r
+MODULE_DESCRIPTION("RK29 Watchdog Device Driver");\r
+MODULE_LICENSE("GPL");\r
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);\r
+MODULE_ALIAS("platform:rk29-wdt");\r