rk29_wdt: fromdos only
authorHuang, Tao <huangtao@rock-chips.com>
Wed, 7 Jan 2015 06:21:55 +0000 (14:21 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 7 Jan 2015 06:22:41 +0000 (14:22 +0800)
Signed-off-by: Huang, Tao <huangtao@rock-chips.com>
drivers/watchdog/rk29_wdt.c

index 78af00773a81c03bbfef57c5694cfb9dbe8ff824..5ed94e5c020df72c4f844f9eb62e76950c67876c 100644 (file)
-/* 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
-#include <asm/mach/map.h>\r
-#ifdef CONFIG_OF\r
-#include <linux/of.h>\r
-#endif\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  = 100;//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 char             expect_close;\r
-\r
-\r
-/* watchdog control routines */\r
-\r
-#define DBG(msg...) do { \\r
-       if (debug) \\r
-               printk(KERN_INFO msg); \\r
-       } while (0)\r
-\r
-#define wdt_writel(v, offset) do { writel_relaxed(v, wdt_base + offset); dsb(); } while (0)\r
-\r
-/* functions */\r
-void rk29_wdt_keepalive(void)\r
-{\r
-       if (wdt_base)\r
-               wdt_writel(0x76, RK29_WDT_CRR);\r
-}\r
-\r
-static void __rk29_wdt_stop(void)\r
-{\r
-       rk29_wdt_keepalive();    //feed dog\r
-       wdt_writel(0x0a, RK29_WDT_CR);\r
-}\r
-\r
-void rk29_wdt_stop(void)\r
-{\r
-       __rk29_wdt_stop();\r
-       clk_disable_unprepare(wdt_clock);\r
-}\r
-\r
-/* timeout unit second */\r
-int rk29_wdt_set_heartbeat(int timeout)\r
-{\r
-       unsigned int count = 0;\r
-       unsigned int torr = 0, acc = 1, maxtime = 0;    \r
-       unsigned int freq = clk_get_rate(wdt_clock);\r
-\r
-       if (timeout < 1)\r
-               return -EINVAL;\r
-       //0x80000000 is the max count of watch dog\r
-       maxtime = 0x80000000 / freq + 1;\r
-       if(timeout > maxtime)\r
-               timeout = maxtime;\r
-               \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:torr:%d, count:%d, maxtime:%d s\n", __func__, torr, count, maxtime);\r
-       wdt_writel(torr, RK29_WDT_TORR);\r
-       return 0;\r
-}\r
-\r
-void rk29_wdt_start(void)\r
-{\r
-       unsigned long wtcon;\r
-       clk_prepare_enable(wdt_clock);\r
-       rk29_wdt_set_heartbeat(tmr_margin);\r
-       wtcon = (RK29_WDT_EN << 0) | (RK29_RESPONSE_MODE << 1) | (RK29_RESET_PULSE << 2);\r
-       wdt_writel(wtcon, RK29_WDT_CR);\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 rk29_wdt_probe(struct platform_device *pdev)\r
-{\r
-       struct resource *res;\r
-       struct device *dev;\r
-       int started = 0;\r
-       int ret, val;\r
-\r
-       dev = &pdev->dev;\r
-       wdt_dev = &pdev->dev;\r
-\r
-       /* get the memory region for the watchdog timer */\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
-       wdt_base = devm_request_and_ioremap(&pdev->dev, res);\r
-       if (wdt_base == NULL) {\r
-               dev_err(dev, "failed to ioremap() region\n");\r
-               return -EINVAL;\r
-       }\r
-       \r
-#ifdef CONFIG_OF\r
-       if(!of_property_read_u32(pdev->dev.of_node, "rockchip,atboot", &val))\r
-               tmr_atboot = val;\r
-       else\r
-               tmr_atboot = 0;\r
-\r
-       if(!of_property_read_u32(pdev->dev.of_node, "rockchip,timeout", &val))\r
-               tmr_margin = val;\r
-       else\r
-               tmr_margin = 0;\r
-\r
-       if(!of_property_read_u32(pdev->dev.of_node, "rockchip,debug", &val))\r
-               debug = val;\r
-       else\r
-               debug = 0;\r
-       DBG("probe: mapped wdt_base=%p\n", wdt_base);\r
-\r
-       of_property_read_u32(pdev->dev.of_node, "rockchip,irq", &val);\r
-#endif\r
-\r
-#ifdef CONFIG_RK29_FEED_DOG_BY_INTE\r
-       val = 1;\r
-#endif\r
-       //printk("atboot:%d, timeout:%ds, debug:%d, irq:%d\n", tmr_atboot, tmr_margin, debug, val);\r
-       \r
-       if(val == 1) {\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
-                       return -ENOENT;\r
-               }\r
-\r
-               ret = request_irq(wdt_irq->start, rk29_wdt_irq_handler, 0, pdev->name, pdev);\r
-               if (ret != 0) {\r
-                       dev_err(dev, "failed to install irq (%d)\n", ret);\r
-                       return ret;\r
-               }\r
-       }\r
-\r
-       wdt_clock = devm_clk_get(&pdev->dev, "pclk_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
-       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_irq;\r
-       }\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
-       return 0;\r
-\r
-err_irq:\r
-       free_irq(wdt_irq->start, pdev);\r
-       return ret;\r
-}\r
-\r
-static int rk29_wdt_remove(struct platform_device *dev)\r
-{\r
-       wdt_mem = NULL;\r
-       free_irq(wdt_irq->start, dev);\r
-       wdt_irq = NULL;\r
-       clk_disable_unprepare(wdt_clock);\r
-       wdt_clock = NULL;\r
-       misc_deregister(&rk29_wdt_miscdev);\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_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
-#ifdef CONFIG_OF\r
-static const struct of_device_id of_rk29_wdt_match[] = {\r
-       { .compatible = "rockchip,watch dog" },\r
-       { /* Sentinel */ }\r
-};\r
-#endif\r
-static struct platform_driver rk29_wdt_driver = {\r
-       .probe          = rk29_wdt_probe,\r
-       .remove         = 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
-#ifdef CONFIG_OF\r
-               .of_match_table = of_rk29_wdt_match,\r
-#endif\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
-subsys_initcall(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
+/* linux/drivers/watchdog/rk29_wdt.c
+ *
+ * Copyright (C) 2011 ROCKCHIP, Inc.
+ *     hhb@rock-chips.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#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 <asm/mach/map.h>
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#endif
+
+
+/* RK29 registers define */
+#define RK29_WDT_CR    0X00
+#define RK29_WDT_TORR  0X04
+#define RK29_WDT_CCVR  0X08
+#define RK29_WDT_CRR   0X0C
+#define RK29_WDT_STAT  0X10
+#define RK29_WDT_EOI   0X14
+
+#define RK29_WDT_EN     1
+#define RK29_RESPONSE_MODE     1
+#define RK29_RESET_PULSE    4
+
+//THAT wdt's clock is 24MHZ
+#define RK29_WDT_2730US        0
+#define RK29_WDT_5460US        1
+#define RK29_WDT_10920US       2
+#define RK29_WDT_21840US       3
+#define RK29_WDT_43680US       4
+#define RK29_WDT_87360US       5
+#define RK29_WDT_174720US      6
+#define RK29_WDT_349440US      7
+#define RK29_WDT_698880US      8
+#define RK29_WDT_1397760US     9
+#define RK29_WDT_2795520US     10
+#define RK29_WDT_5591040US     11
+#define RK29_WDT_11182080US    12
+#define RK29_WDT_22364160US    13
+#define RK29_WDT_44728320US    14
+#define RK29_WDT_89456640US    15
+
+/*
+#define CONFIG_RK29_WATCHDOG_ATBOOT            (1)
+#define CONFIG_RK29_WATCHDOG_DEFAULT_TIME      10      //unit second
+#define CONFIG_RK29_WATCHDOG_DEBUG     1
+*/
+
+static int nowayout    = WATCHDOG_NOWAYOUT;
+static int tmr_margin  = 100;//CONFIG_RK29_WATCHDOG_DEFAULT_TIME;
+#ifdef CONFIG_RK29_WATCHDOG_ATBOOT
+static int tmr_atboot  = 1;
+#else
+static int tmr_atboot  = 0;
+#endif
+
+static int soft_noboot;
+
+#ifdef CONFIG_RK29_WATCHDOG_DEBUG
+static int debug       = 1;
+#else
+static int debug       = 0;
+#endif
+
+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_RK29_WATCHDOG_DEFAULT_TIME) ")");
+MODULE_PARM_DESC(tmr_atboot,
+               "Watchdog is started at boot time if set to 1, default="
+                       __MODULE_STRING(CONFIG_RK29_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;      /* 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 char             expect_close;
+
+
+/* watchdog control routines */
+
+#define DBG(msg...) do { \
+       if (debug) \
+               printk(KERN_INFO msg); \
+       } while (0)
+
+#define wdt_writel(v, offset) do { writel_relaxed(v, wdt_base + offset); dsb(); } while (0)
+
+/* functions */
+void rk29_wdt_keepalive(void)
+{
+       if (wdt_base)
+               wdt_writel(0x76, RK29_WDT_CRR);
+}
+
+static void __rk29_wdt_stop(void)
+{
+       rk29_wdt_keepalive();    //feed dog
+       wdt_writel(0x0a, RK29_WDT_CR);
+}
+
+void rk29_wdt_stop(void)
+{
+       __rk29_wdt_stop();
+       clk_disable_unprepare(wdt_clock);
+}
+
+/* timeout unit second */
+int rk29_wdt_set_heartbeat(int timeout)
+{
+       unsigned int count = 0;
+       unsigned int torr = 0, acc = 1, maxtime = 0;    
+       unsigned int freq = clk_get_rate(wdt_clock);
+
+       if (timeout < 1)
+               return -EINVAL;
+       //0x80000000 is the max count of watch dog
+       maxtime = 0x80000000 / freq + 1;
+       if(timeout > maxtime)
+               timeout = maxtime;
+               
+       count = timeout * freq;
+       count /= 0x10000;
+
+       while(acc < count){
+               acc *= 2;
+               torr++;
+       }
+       if(torr > 15){
+               torr = 15;
+       }
+       DBG("%s:torr:%d, count:%d, maxtime:%d s\n", __func__, torr, count, maxtime);
+       wdt_writel(torr, RK29_WDT_TORR);
+       return 0;
+}
+
+void rk29_wdt_start(void)
+{
+       unsigned long wtcon;
+       clk_prepare_enable(wdt_clock);
+       rk29_wdt_set_heartbeat(tmr_margin);
+       wtcon = (RK29_WDT_EN << 0) | (RK29_RESPONSE_MODE << 1) | (RK29_RESET_PULSE << 2);
+       wdt_writel(wtcon, RK29_WDT_CR);
+}
+
+/*
+ *     /dev/watchdog handling
+ */
+
+static int rk29_wdt_open(struct inode *inode, struct file *file)
+{
+       DBG("%s\n", __func__);
+       if (test_and_set_bit(0, &open_lock))
+               return -EBUSY;
+
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       expect_close = 0;
+
+       /* start the timer */
+       rk29_wdt_start();
+       return nonseekable_open(inode, file);
+}
+
+static int rk29_wdt_release(struct inode *inode, struct file *file)
+{
+       /*
+        *      Shut off the timer.
+        *      Lock it in if it's a module and we set nowayout
+        */
+       DBG("%s\n", __func__);
+       if (expect_close == 42)
+               rk29_wdt_stop();
+       else {
+               dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");
+               rk29_wdt_keepalive();
+       }
+       expect_close = 0;
+       clear_bit(0, &open_lock);
+       return 0;
+}
+
+static ssize_t rk29_wdt_write(struct file *file, const char __user *data,
+                               size_t len, loff_t *ppos)
+{
+       /*
+        *      Refresh the timer.
+        */
+       DBG("%s\n", __func__);
+       if (len) {
+               if (!nowayout) {
+                       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;
+                       }
+               }
+               rk29_wdt_keepalive();
+       }
+       return len;
+}
+
+#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
+
+static const struct watchdog_info rk29_wdt_ident = {
+       .options          =     OPTIONS,
+       .firmware_version =     0,
+       .identity         =     "rk29 Watchdog",
+};
+
+
+static long rk29_wdt_ioctl(struct file *file,  unsigned int cmd,
+                                                       unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_margin;
+       DBG("%s\n", __func__);
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &rk29_wdt_ident,
+                       sizeof(rk29_wdt_ident)) ? -EFAULT : 0;
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+       case WDIOC_KEEPALIVE:
+               DBG("%s:rk29_wdt_keepalive\n", __func__);
+               rk29_wdt_keepalive();
+               return 0;
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_margin, p))
+                       return -EFAULT;
+               if (rk29_wdt_set_heartbeat(new_margin))
+                       return -EINVAL;
+               rk29_wdt_keepalive();
+               return put_user(tmr_margin, p);
+       case WDIOC_GETTIMEOUT:
+               return put_user(tmr_margin, p);
+       default:
+               return -ENOTTY;
+       }
+}
+
+
+
+/* kernel interface */
+
+static const struct file_operations rk29_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = rk29_wdt_write,
+       .unlocked_ioctl = rk29_wdt_ioctl,
+       .open           = rk29_wdt_open,
+       .release        = rk29_wdt_release,
+};
+
+static struct miscdevice rk29_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &rk29_wdt_fops,
+};
+
+
+/* interrupt handler code */
+
+static irqreturn_t rk29_wdt_irq_handler(int irqno, void *param)
+{
+       DBG("RK29_wdt:watchdog timer expired (irq)\n");
+       rk29_wdt_keepalive();
+       return IRQ_HANDLED;
+}
+
+
+/* device interface */
+
+static int rk29_wdt_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct device *dev;
+       int started = 0;
+       int ret, val;
+
+       dev = &pdev->dev;
+       wdt_dev = &pdev->dev;
+
+       /* get the memory region for the watchdog timer */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "no memory resource specified\n");
+               return -ENOENT;
+       }
+
+       wdt_base = devm_request_and_ioremap(&pdev->dev, res);
+       if (wdt_base == NULL) {
+               dev_err(dev, "failed to ioremap() region\n");
+               return -EINVAL;
+       }
+       
+#ifdef CONFIG_OF
+       if(!of_property_read_u32(pdev->dev.of_node, "rockchip,atboot", &val))
+               tmr_atboot = val;
+       else
+               tmr_atboot = 0;
+
+       if(!of_property_read_u32(pdev->dev.of_node, "rockchip,timeout", &val))
+               tmr_margin = val;
+       else
+               tmr_margin = 0;
+
+       if(!of_property_read_u32(pdev->dev.of_node, "rockchip,debug", &val))
+               debug = val;
+       else
+               debug = 0;
+       DBG("probe: mapped wdt_base=%p\n", wdt_base);
+
+       of_property_read_u32(pdev->dev.of_node, "rockchip,irq", &val);
+#endif
+
+#ifdef CONFIG_RK29_FEED_DOG_BY_INTE
+       val = 1;
+#endif
+       //printk("atboot:%d, timeout:%ds, debug:%d, irq:%d\n", tmr_atboot, tmr_margin, debug, val);
+       
+       if(val == 1) {
+               wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+               if (wdt_irq == NULL) {
+                       dev_err(dev, "no irq resource specified\n");
+                       return -ENOENT;
+               }
+
+               ret = request_irq(wdt_irq->start, rk29_wdt_irq_handler, 0, pdev->name, pdev);
+               if (ret != 0) {
+                       dev_err(dev, "failed to install irq (%d)\n", ret);
+                       return ret;
+               }
+       }
+
+       wdt_clock = devm_clk_get(&pdev->dev, "pclk_wdt");
+       if (IS_ERR(wdt_clock)) {
+               dev_err(dev, "failed to find watchdog clock source\n");
+               ret = PTR_ERR(wdt_clock);
+               goto err_irq;
+       }
+
+       ret = misc_register(&rk29_wdt_miscdev);
+       if (ret) {
+               dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
+                       WATCHDOG_MINOR, ret);
+               goto err_irq;
+       }
+       if (tmr_atboot && started == 0) {
+               dev_info(dev, "starting watchdog timer\n");
+               rk29_wdt_start();
+       } else if (!tmr_atboot) {
+               /* if we're not enabling the watchdog, then ensure it is
+                * disabled if it has been left running from the bootloader
+                * or other source */
+
+               rk29_wdt_stop();
+       }
+       return 0;
+
+err_irq:
+       free_irq(wdt_irq->start, pdev);
+       return ret;
+}
+
+static int rk29_wdt_remove(struct platform_device *dev)
+{
+       wdt_mem = NULL;
+       free_irq(wdt_irq->start, dev);
+       wdt_irq = NULL;
+       clk_disable_unprepare(wdt_clock);
+       wdt_clock = NULL;
+       misc_deregister(&rk29_wdt_miscdev);
+       return 0;
+}
+
+static void rk29_wdt_shutdown(struct platform_device *dev)
+{
+       rk29_wdt_stop();
+}
+
+#ifdef CONFIG_PM
+
+static int rk29_wdt_suspend(struct platform_device *dev, pm_message_t state)
+{
+       rk29_wdt_stop();
+       return 0;
+}
+
+static int rk29_wdt_resume(struct platform_device *dev)
+{
+       rk29_wdt_start();
+       return 0;
+}
+
+#else
+#define rk29_wdt_suspend NULL
+#define rk29_wdt_resume  NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_rk29_wdt_match[] = {
+       { .compatible = "rockchip,watch dog" },
+       { /* Sentinel */ }
+};
+#endif
+static struct platform_driver rk29_wdt_driver = {
+       .probe          = rk29_wdt_probe,
+       .remove         = rk29_wdt_remove,
+       .shutdown       = rk29_wdt_shutdown,
+       .suspend        = rk29_wdt_suspend,
+       .resume         = rk29_wdt_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_OF
+               .of_match_table = of_rk29_wdt_match,
+#endif
+               .name   = "rk29-wdt",
+       },
+};
+
+
+static char banner[] __initdata =
+       KERN_INFO "RK29 Watchdog Timer, (c) 2011 Rockchip Electronics\n";
+
+static int __init watchdog_init(void)
+{
+       printk(banner);
+       return platform_driver_register(&rk29_wdt_driver);
+}
+
+static void __exit watchdog_exit(void)
+{
+       platform_driver_unregister(&rk29_wdt_driver);
+}
+
+subsys_initcall(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("hhb@rock-chips.com");
+MODULE_DESCRIPTION("RK29 Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:rk29-wdt");