aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/Kconfig10
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/bcm63xx_wdt.c350
3 files changed, 361 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 57b8a410697b..4a291045ebac 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -917,6 +917,16 @@ config OCTEON_WDT
917 from the first interrupt, it is then only poked when the 917 from the first interrupt, it is then only poked when the
918 device is written. 918 device is written.
919 919
920config BCM63XX_WDT
921 tristate "Broadcom BCM63xx hardware watchdog"
922 depends on BCM63XX
923 help
924 Watchdog driver for the built in watchdog hardware in Broadcom
925 BCM63xx SoC.
926
927 To compile this driver as a loadable module, choose M here.
928 The module will be called bcm63xx_wdt.
929
920# PARISC Architecture 930# PARISC Architecture
921 931
922# POWERPC Architecture 932# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 8374503fcc6a..4b0ef386229d 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -109,6 +109,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
109 109
110# MIPS Architecture 110# MIPS Architecture
111obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o 111obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
112obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
112obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o 113obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
113obj-$(CONFIG_INDYDOG) += indydog.o 114obj-$(CONFIG_INDYDOG) += indydog.o
114obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o 115obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c
new file mode 100644
index 000000000000..a1debc89356b
--- /dev/null
+++ b/drivers/watchdog/bcm63xx_wdt.c
@@ -0,0 +1,350 @@
1/*
2 * Broadcom BCM63xx SoC watchdog driver
3 *
4 * Copyright (C) 2007, Miguel Gaio <miguel.gaio@efixo.com>
5 * Copyright (C) 2008, Florian Fainelli <florian@openwrt.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/bitops.h>
14#include <linux/errno.h>
15#include <linux/fs.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/miscdevice.h>
19#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/reboot.h>
22#include <linux/types.h>
23#include <linux/uaccess.h>
24#include <linux/watchdog.h>
25#include <linux/timer.h>
26#include <linux/jiffies.h>
27#include <linux/interrupt.h>
28#include <linux/ptrace.h>
29#include <linux/resource.h>
30#include <linux/platform_device.h>
31
32#include <bcm63xx_cpu.h>
33#include <bcm63xx_io.h>
34#include <bcm63xx_regs.h>
35#include <bcm63xx_timer.h>
36
37#define PFX KBUILD_MODNAME
38
39#define WDT_HZ 50000000 /* Fclk */
40#define WDT_DEFAULT_TIME 30 /* seconds */
41#define WDT_MAX_TIME 256 /* seconds */
42
43static struct {
44 void __iomem *regs;
45 struct timer_list timer;
46 int default_ticks;
47 unsigned long inuse;
48 atomic_t ticks;
49} bcm63xx_wdt_device;
50
51static int expect_close;
52
53static int wdt_time = WDT_DEFAULT_TIME;
54static int nowayout = WATCHDOG_NOWAYOUT;
55module_param(nowayout, int, 0);
56MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
57 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
58
59/* HW functions */
60static void bcm63xx_wdt_hw_start(void)
61{
62 bcm_writel(0xfffffffe, bcm63xx_wdt_device.regs + WDT_DEFVAL_REG);
63 bcm_writel(WDT_START_1, bcm63xx_wdt_device.regs + WDT_CTL_REG);
64 bcm_writel(WDT_START_2, bcm63xx_wdt_device.regs + WDT_CTL_REG);
65}
66
67static void bcm63xx_wdt_hw_stop(void)
68{
69 bcm_writel(WDT_STOP_1, bcm63xx_wdt_device.regs + WDT_CTL_REG);
70 bcm_writel(WDT_STOP_2, bcm63xx_wdt_device.regs + WDT_CTL_REG);
71}
72
73static void bcm63xx_wdt_isr(void *data)
74{
75 struct pt_regs *regs = get_irq_regs();
76
77 die(PFX " fire", regs);
78}
79
80static void bcm63xx_timer_tick(unsigned long unused)
81{
82 if (!atomic_dec_and_test(&bcm63xx_wdt_device.ticks)) {
83 bcm63xx_wdt_hw_start();
84 mod_timer(&bcm63xx_wdt_device.timer, jiffies + HZ);
85 } else
86 printk(KERN_CRIT PFX ": watchdog will restart system\n");
87}
88
89static void bcm63xx_wdt_pet(void)
90{
91 atomic_set(&bcm63xx_wdt_device.ticks, wdt_time);
92}
93
94static void bcm63xx_wdt_start(void)
95{
96 bcm63xx_wdt_pet();
97 bcm63xx_timer_tick(0);
98}
99
100static void bcm63xx_wdt_pause(void)
101{
102 del_timer_sync(&bcm63xx_wdt_device.timer);
103 bcm63xx_wdt_hw_stop();
104}
105
106static int bcm63xx_wdt_settimeout(int new_time)
107{
108 if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
109 return -EINVAL;
110
111 wdt_time = new_time;
112
113 return 0;
114}
115
116static int bcm63xx_wdt_open(struct inode *inode, struct file *file)
117{
118 if (test_and_set_bit(0, &bcm63xx_wdt_device.inuse))
119 return -EBUSY;
120
121 bcm63xx_wdt_start();
122 return nonseekable_open(inode, file);
123}
124
125static int bcm63xx_wdt_release(struct inode *inode, struct file *file)
126{
127 if (expect_close == 42)
128 bcm63xx_wdt_pause();
129 else {
130 printk(KERN_CRIT PFX
131 ": Unexpected close, not stopping watchdog!\n");
132 bcm63xx_wdt_start();
133 }
134 clear_bit(0, &bcm63xx_wdt_device.inuse);
135 expect_close = 0;
136 return 0;
137}
138
139static ssize_t bcm63xx_wdt_write(struct file *file, const char *data,
140 size_t len, loff_t *ppos)
141{
142 if (len) {
143 if (!nowayout) {
144 size_t i;
145
146 /* In case it was set long ago */
147 expect_close = 0;
148
149 for (i = 0; i != len; i++) {
150 char c;
151 if (get_user(c, data + i))
152 return -EFAULT;
153 if (c == 'V')
154 expect_close = 42;
155 }
156 }
157 bcm63xx_wdt_pet();
158 }
159 return len;
160}
161
162static struct watchdog_info bcm63xx_wdt_info = {
163 .identity = PFX,
164 .options = WDIOF_SETTIMEOUT |
165 WDIOF_KEEPALIVEPING |
166 WDIOF_MAGICCLOSE,
167};