aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5pv210/herring-watchdog.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s5pv210/herring-watchdog.c')
-rw-r--r--arch/arm/mach-s5pv210/herring-watchdog.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/arch/arm/mach-s5pv210/herring-watchdog.c b/arch/arm/mach-s5pv210/herring-watchdog.c
new file mode 100644
index 0000000..7ff9fee
--- /dev/null
+++ b/arch/arm/mach-s5pv210/herring-watchdog.c
@@ -0,0 +1,111 @@
+/* herring-watchdog.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <plat/regs-watchdog.h>
+#include <mach/map.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+
+/* reset timeout in PCLK/256/128 (~2048:1s) */
+static unsigned watchdog_reset = (30 * 2048);
+
+/* pet timeout in jiffies */
+static unsigned watchdog_pet = (10 * HZ);
+
+static struct workqueue_struct *watchdog_wq;
+static void watchdog_workfunc(struct work_struct *work);
+static DECLARE_DELAYED_WORK(watchdog_work, watchdog_workfunc);
+
+static void watchdog_workfunc(struct work_struct *work)
+{
+ writel(watchdog_reset, S3C2410_WTCNT);
+ queue_delayed_work(watchdog_wq, &watchdog_work, watchdog_pet);
+}
+
+static void watchdog_start(void)
+{
+ unsigned int val;
+
+ /* set to PCLK / 256 / 128 */
+ val = S3C2410_WTCON_DIV128;
+ val |= S3C2410_WTCON_PRESCALE(255);
+ writel(val, S3C2410_WTCON);
+
+ /* program initial count */
+ writel(watchdog_reset, S3C2410_WTCNT);
+ writel(watchdog_reset, S3C2410_WTDAT);
+
+ /* start timer */
+ val |= S3C2410_WTCON_RSTEN | S3C2410_WTCON_ENABLE;
+ writel(val, S3C2410_WTCON);
+
+ /* make sure we're ready to pet the dog */
+ queue_delayed_work(watchdog_wq, &watchdog_work, watchdog_pet);
+}
+
+static void watchdog_stop(void)
+{
+ writel(0, S3C2410_WTCON);
+}
+
+static int watchdog_probe(struct platform_device *pdev)
+{
+ watchdog_wq = alloc_workqueue("pet_watchdog",
+ WQ_UNBOUND | WQ_HIGHPRI, 1);
+ watchdog_start();
+ return 0;
+}
+
+static int watchdog_suspend(struct device *dev)
+{
+ watchdog_stop();
+ return 0;
+}
+
+static int watchdog_resume(struct device *dev)
+{
+ watchdog_start();
+ return 0;
+}
+
+static struct dev_pm_ops watchdog_pm_ops = {
+ .suspend_noirq = watchdog_suspend,
+ .resume_noirq = watchdog_resume,
+};
+
+static struct platform_driver watchdog_driver = {
+ .probe = watchdog_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "watchdog",
+ .pm = &watchdog_pm_ops,
+ },
+};
+
+static int __init watchdog_init(void)
+{
+ return platform_driver_register(&watchdog_driver);
+}
+
+module_init(watchdog_init);