aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2013-10-28 22:43:57 -0400
committerWim Van Sebroeck <wim@iguana.be>2013-11-18 15:34:01 -0500
commit30a83695aa2ed3ffb1445d6daef1e620c3ca4e6d (patch)
tree26ec7029822b66a043c5230f7711e1998ebb684b
parent4a7e94a0637da7e1ddce748da49ae780c370eeef (diff)
watchdog: w83627hf: Convert to watchdog infrastructure
Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/w83627hf_wdt.c215
2 files changed, 48 insertions, 168 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 74f29a2fc51c..5be6e919f785 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -885,6 +885,7 @@ config VIA_WDT
885config W83627HF_WDT 885config W83627HF_WDT
886 tristate "W83627HF/W83627DHG Watchdog Timer" 886 tristate "W83627HF/W83627DHG Watchdog Timer"
887 depends on X86 887 depends on X86
888 select WATCHDOG_CORE
888 ---help--- 889 ---help---
889 This is the driver for the hardware watchdog on the W83627HF chipset 890 This is the driver for the hardware watchdog on the W83627HF chipset
890 as used in Advantech PC-9578 and Tyan S2721-533 motherboards 891 as used in Advantech PC-9578 and Tyan S2721-533 motherboards
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index da6781c12523..ab5ec6d84b16 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -1,6 +1,9 @@
1/* 1/*
2 * w83627hf/thf WDT driver 2 * w83627hf/thf WDT driver
3 * 3 *
4 * (c) Copyright 2013 Guenter Roeck
5 * converted to watchdog infrastructure
6 *
4 * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> 7 * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
5 * added support for W83627THF. 8 * added support for W83627THF.
6 * 9 *
@@ -31,31 +34,22 @@
31#include <linux/module.h> 34#include <linux/module.h>
32#include <linux/moduleparam.h> 35#include <linux/moduleparam.h>
33#include <linux/types.h> 36#include <linux/types.h>
34#include <linux/miscdevice.h>
35#include <linux/watchdog.h> 37#include <linux/watchdog.h>
36#include <linux/fs.h>
37#include <linux/ioport.h> 38#include <linux/ioport.h>
38#include <linux/notifier.h> 39#include <linux/notifier.h>
39#include <linux/reboot.h> 40#include <linux/reboot.h>
40#include <linux/init.h> 41#include <linux/init.h>
41#include <linux/spinlock.h>
42#include <linux/io.h> 42#include <linux/io.h>
43#include <linux/uaccess.h>
44
45 43
46#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" 44#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
47#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ 45#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
48 46
49static unsigned long wdt_is_open;
50static char expect_close;
51static DEFINE_SPINLOCK(io_lock);
52
53/* You must set this - there is no sane way to probe for this board. */ 47/* You must set this - there is no sane way to probe for this board. */
54static int wdt_io = 0x2E; 48static int wdt_io = 0x2E;
55module_param(wdt_io, int, 0); 49module_param(wdt_io, int, 0);
56MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); 50MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
57 51
58static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ 52static int timeout; /* in seconds */
59module_param(timeout, int, 0); 53module_param(timeout, int, 0);
60MODULE_PARM_DESC(timeout, 54MODULE_PARM_DESC(timeout,
61 "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" 55 "Watchdog timeout in seconds. 1 <= timeout <= 255, default="
@@ -110,7 +104,7 @@ static void w83627hf_unselect_wd_register(void)
110/* tyan motherboards seem to set F5 to 0x4C ? 104/* tyan motherboards seem to set F5 to 0x4C ?
111 * So explicitly init to appropriate value. */ 105 * So explicitly init to appropriate value. */
112 106
113static void w83627hf_init(void) 107static void w83627hf_init(struct watchdog_device *wdog)
114{ 108{
115 unsigned char t; 109 unsigned char t;
116 110
@@ -120,8 +114,8 @@ static void w83627hf_init(void)
120 t = inb_p(WDT_EFDR); /* read CRF6 */ 114 t = inb_p(WDT_EFDR); /* read CRF6 */
121 if (t != 0) { 115 if (t != 0) {
122 pr_info("Watchdog already running. Resetting timeout to %d sec\n", 116 pr_info("Watchdog already running. Resetting timeout to %d sec\n",
123 timeout); 117 wdog->timeout);
124 outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ 118 outb_p(wdog->timeout, WDT_EFDR); /* Write back to CRF6 */
125 } 119 }
126 120
127 outb_p(0xF5, WDT_EFER); /* Select CRF5 */ 121 outb_p(0xF5, WDT_EFER); /* Select CRF5 */
@@ -141,10 +135,8 @@ static void w83627hf_init(void)
141 w83627hf_unselect_wd_register(); 135 w83627hf_unselect_wd_register();
142} 136}
143 137
144static void wdt_set_time(int timeout) 138static int wdt_set_time(unsigned int timeout)
145{ 139{
146 spin_lock(&io_lock);
147
148 w83627hf_select_wd_register(); 140 w83627hf_select_wd_register();
149 141
150 outb_p(0xF6, WDT_EFER); /* Select CRF6 */ 142 outb_p(0xF6, WDT_EFER); /* Select CRF6 */
@@ -152,34 +144,29 @@ static void wdt_set_time(int timeout)
152 144
153 w83627hf_unselect_wd_register(); 145 w83627hf_unselect_wd_register();
154 146
155 spin_unlock(&io_lock); 147 return 0;
156} 148}
157 149
158static int wdt_ping(void) 150static int wdt_start(struct watchdog_device *wdog)
159{ 151{
160 wdt_set_time(timeout); 152 return wdt_set_time(wdog->timeout);
161 return 0;
162} 153}
163 154
164static int wdt_disable(void) 155static int wdt_stop(struct watchdog_device *wdog)
165{ 156{
166 wdt_set_time(0); 157 return wdt_set_time(0);
167 return 0;
168} 158}
169 159
170static int wdt_set_heartbeat(int t) 160static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
171{ 161{
172 if (t < 1 || t > 255) 162 wdog->timeout = timeout;
173 return -EINVAL; 163
174 timeout = t;
175 return 0; 164 return 0;
176} 165}
177 166
178static int wdt_get_time(void) 167static unsigned int wdt_get_time(struct watchdog_device *wdog)
179{ 168{
180 int timeleft; 169 unsigned int timeleft;
181
182 spin_lock(&io_lock);
183 170
184 w83627hf_select_wd_register(); 171 w83627hf_select_wd_register();
185 172
@@ -188,124 +175,17 @@ static int wdt_get_time(void)
188 175
189 w83627hf_unselect_wd_register(); 176 w83627hf_unselect_wd_register();
190 177
191 spin_unlock(&io_lock);
192
193 return timeleft; 178 return timeleft;
194} 179}
195 180
196static ssize_t wdt_write(struct file *file, const char __user *buf,
197 size_t count, loff_t *ppos)
198{
199 if (count) {
200 if (!nowayout) {
201 size_t i;
202
203 expect_close = 0;
204
205 for (i = 0; i != count; i++) {
206 char c;
207 if (get_user(c, buf + i))
208 return -EFAULT;
209 if (c == 'V')
210 expect_close = 42;
211 }
212 }
213 wdt_ping();
214 }
215 return count;
216}
217
218static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
219{
220 void __user *argp = (void __user *)arg;
221 int __user *p = argp;
222 int timeval;
223 static const struct watchdog_info ident = {
224 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
225 WDIOF_MAGICCLOSE,
226 .firmware_version = 1,
227 .identity = "W83627HF WDT",
228 };
229
230 switch (cmd) {
231 case WDIOC_GETSUPPORT:
232 if (copy_to_user(argp, &ident, sizeof(ident)))
233 return -EFAULT;
234 break;
235 case WDIOC_GETSTATUS:
236 case WDIOC_GETBOOTSTATUS:
237 return put_user(0, p);
238 case WDIOC_SETOPTIONS:
239 {
240 int options, retval = -EINVAL;
241
242 if (get_user(options, p))
243 return -EFAULT;
244 if (options & WDIOS_DISABLECARD) {
245 wdt_disable();
246 retval = 0;
247 }
248 if (options & WDIOS_ENABLECARD) {
249 wdt_ping();
250 retval = 0;
251 }
252 return retval;
253 }
254 case WDIOC_KEEPALIVE:
255 wdt_ping();
256 break;
257 case WDIOC_SETTIMEOUT:
258 if (get_user(timeval, p))
259 return -EFAULT;
260 if (wdt_set_heartbeat(timeval))
261 return -EINVAL;
262 wdt_ping();
263 /* Fall */
264 case WDIOC_GETTIMEOUT:
265 return put_user(timeout, p);
266 case WDIOC_GETTIMELEFT:
267 timeval = wdt_get_time();
268 return put_user(timeval, p);
269 default:
270 return -ENOTTY;
271 }
272 return 0;
273}
274
275static int wdt_open(struct inode *inode, struct file *file)
276{
277 if (test_and_set_bit(0, &wdt_is_open))
278 return -EBUSY;
279 /*
280 * Activate
281 */
282
283 wdt_ping();
284 return nonseekable_open(inode, file);
285}
286
287static int wdt_close(struct inode *inode, struct file *file)
288{
289 if (expect_close == 42)
290 wdt_disable();
291 else {
292 pr_crit("Unexpected close, not stopping watchdog!\n");
293 wdt_ping();
294 }
295 expect_close = 0;
296 clear_bit(0, &wdt_is_open);
297 return 0;
298}
299
300/* 181/*
301 * Notifier for system down 182 * Notifier for system down
302 */ 183 */
303
304static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 184static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
305 void *unused) 185 void *unused)
306{ 186{
307 if (code == SYS_DOWN || code == SYS_HALT) 187 if (code == SYS_DOWN || code == SYS_HALT)
308 wdt_disable(); /* Turn the WDT off */ 188 wdt_set_time(0); /* Turn the WDT off */
309 189
310 return NOTIFY_DONE; 190 return NOTIFY_DONE;
311} 191}
@@ -314,19 +194,25 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
314 * Kernel Interfaces 194 * Kernel Interfaces
315 */ 195 */
316 196
317static const struct file_operations wdt_fops = { 197static struct watchdog_info wdt_info = {
318 .owner = THIS_MODULE, 198 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
319 .llseek = no_llseek, 199 .identity = "W83627HF Watchdog",
320 .write = wdt_write,
321 .unlocked_ioctl = wdt_ioctl,
322 .open = wdt_open,
323 .release = wdt_close,
324}; 200};
325 201
326static struct miscdevice wdt_miscdev = { 202static struct watchdog_ops wdt_ops = {
327 .minor = WATCHDOG_MINOR, 203 .owner = THIS_MODULE,
328 .name = "watchdog", 204 .start = wdt_start,
329 .fops = &wdt_fops, 205 .stop = wdt_stop,
206 .set_timeout = wdt_set_timeout,
207 .get_timeleft = wdt_get_time,
208};
209
210static struct watchdog_device wdt_dev = {
211 .info = &wdt_info,
212 .ops = &wdt_ops,
213 .timeout = WATCHDOG_TIMEOUT,
214 .min_timeout = 1,
215 .max_timeout = 255,
330}; 216};
331 217
332/* 218/*
@@ -344,19 +230,15 @@ static int __init wdt_init(void)
344 230
345 pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); 231 pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n");
346 232
347 if (wdt_set_heartbeat(timeout)) {
348 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
349 pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
350 WATCHDOG_TIMEOUT);
351 }
352
353 if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { 233 if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
354 pr_err("I/O address 0x%04x already in use\n", wdt_io); 234 pr_err("I/O address 0x%04x already in use\n", wdt_io);
355 ret = -EIO; 235 return -EIO;
356 goto out;
357 } 236 }
358 237
359 w83627hf_init(); 238 watchdog_init_timeout(&wdt_dev, timeout, NULL);
239 watchdog_set_nowayout(&wdt_dev, nowayout);
240
241 w83627hf_init(&wdt_dev);
360 242
361 ret = register_reboot_notifier(&wdt_notifier); 243 ret = register_reboot_notifier(&wdt_notifier);
362 if (ret != 0) { 244 if (ret != 0) {
@@ -364,28 +246,25 @@ static int __init wdt_init(void)
364 goto unreg_regions; 246 goto unreg_regions;
365 } 247 }
366 248
367 ret = misc_register(&wdt_miscdev); 249 ret = watchdog_register_device(&wdt_dev);
368 if (ret != 0) { 250 if (ret)
369 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
370 WATCHDOG_MINOR, ret);
371 goto unreg_reboot; 251 goto unreg_reboot;
372 }
373 252
374 pr_info("initialized. timeout=%d sec (nowayout=%d)\n", 253 pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
375 timeout, nowayout); 254 wdt_dev.timeout, nowayout);
376 255
377out:
378 return ret; 256 return ret;
257
379unreg_reboot: 258unreg_reboot:
380 unregister_reboot_notifier(&wdt_notifier); 259 unregister_reboot_notifier(&wdt_notifier);
381unreg_regions: 260unreg_regions:
382 release_region(wdt_io, 1); 261 release_region(wdt_io, 1);
383 goto out; 262 return ret;
384} 263}
385 264
386static void __exit wdt_exit(void) 265static void __exit wdt_exit(void)
387{ 266{
388 misc_deregister(&wdt_miscdev); 267 watchdog_unregister_device(&wdt_dev);
389 unregister_reboot_notifier(&wdt_notifier); 268 unregister_reboot_notifier(&wdt_notifier);
390 release_region(wdt_io, 1); 269 release_region(wdt_io, 1);
391} 270}