Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
[WATCHDOG] orion5x_wdt.c: add spinlocking
[WATCHDOG] Orion: add hardware watchdog support
[WATCHDOG] omap_wdt.c: cleanup a bit omap_wdt.c
[WATCHDOG] omap_wdt.c: another ioremap() fix
[WATCHDOG] omap_wdt.c: sync linux-omap changes
[WATCHDOG] Add AT91SAM9X watchdog
[WATCHDOG] Add driver for winbond w83697ug/uf watchdog feature
[WATCHDOG] add watchdog driver IT8716 IT8726 IT8712J/K

+1987 -142
+2
arch/arm/mach-orion5x/include/mach/orion5x.h
··· 157 157 #define CPU_CONF ORION5X_BRIDGE_REG(0x100) 158 158 #define CPU_CTRL ORION5X_BRIDGE_REG(0x104) 159 159 #define CPU_RESET_MASK ORION5X_BRIDGE_REG(0x108) 160 + #define WDT_RESET 0x0002 160 161 #define CPU_SOFT_RESET ORION5X_BRIDGE_REG(0x10c) 161 162 #define POWER_MNG_CTRL_REG ORION5X_BRIDGE_REG(0x11C) 162 163 #define BRIDGE_CAUSE ORION5X_BRIDGE_REG(0x110) 164 + #define WDT_INT_REQ 0x0008 163 165 #define BRIDGE_MASK ORION5X_BRIDGE_REG(0x114) 164 166 #define BRIDGE_INT_TIMER0 0x0002 165 167 #define BRIDGE_INT_TIMER1 0x0004
+13 -8
arch/arm/plat-omap/devices.c
··· 441 441 442 442 #if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE) 443 443 444 - #ifdef CONFIG_ARCH_OMAP24XX 445 - #define OMAP_WDT_BASE 0x48022000 446 - #else 447 - #define OMAP_WDT_BASE 0xfffeb000 448 - #endif 449 - 450 444 static struct resource wdt_resources[] = { 451 445 { 452 - .start = OMAP_WDT_BASE, 453 - .end = OMAP_WDT_BASE + 0x4f, 454 446 .flags = IORESOURCE_MEM, 455 447 }, 456 448 }; ··· 456 464 457 465 static void omap_init_wdt(void) 458 466 { 467 + if (cpu_is_omap16xx()) 468 + wdt_resources[0].start = 0xfffeb000; 469 + else if (cpu_is_omap2420()) 470 + wdt_resources[0].start = 0x48022000; /* WDT2 */ 471 + else if (cpu_is_omap2430()) 472 + wdt_resources[0].start = 0x49016000; /* WDT2 */ 473 + else if (cpu_is_omap343x()) 474 + wdt_resources[0].start = 0x48314000; /* WDT2 */ 475 + else 476 + return; 477 + 478 + wdt_resources[0].end = wdt_resources[0].start + 0x4f; 479 + 459 480 (void) platform_device_register(&omap_wdt_device); 460 481 } 461 482 #else
+43
drivers/watchdog/Kconfig
··· 66 66 Watchdog timer embedded into AT91RM9200 chips. This will reboot your 67 67 system when the timeout is reached. 68 68 69 + config AT91SAM9X_WATCHDOG 70 + tristate "AT91SAM9X watchdog" 71 + depends on WATCHDOG && (ARCH_AT91SAM9260 || ARCH_AT91SAM9261) 72 + help 73 + Watchdog timer embedded into AT91SAM9X chips. This will reboot your 74 + system when the timeout is reached. 75 + 69 76 config 21285_WATCHDOG 70 77 tristate "DC21285 watchdog" 71 78 depends on FOOTBRIDGE ··· 223 216 224 217 NOTE: once enabled, this timer cannot be disabled. 225 218 Say N if you are unsure. 219 + 220 + config ORION5X_WATCHDOG 221 + tristate "Orion5x watchdog" 222 + depends on ARCH_ORION5X 223 + help 224 + Say Y here if to include support for the watchdog timer 225 + in the Orion5x ARM SoCs. 226 + To compile this driver as a module, choose M here: the 227 + module will be called orion5x_wdt. 226 228 227 229 # ARM26 Architecture 228 230 ··· 432 416 To compile this driver as a module, choose M here: the 433 417 module will be called it8712f_wdt. 434 418 419 + config IT87_WDT 420 + tristate "IT87 Watchdog Timer" 421 + depends on X86 && EXPERIMENTAL 422 + ---help--- 423 + This is the driver for the hardware watchdog on the ITE IT8716, 424 + IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog 425 + simply watches your kernel to make sure it doesn't freeze, and if 426 + it does, it reboots your computer after a certain amount of time. 427 + 428 + To compile this driver as a module, choose M here: the module will 429 + be called it87_wdt. 430 + 435 431 config HP_WATCHDOG 436 432 tristate "HP Proliant iLO 2 Hardware Watchdog Timer" 437 433 depends on X86 ··· 598 570 599 571 To compile this driver as a module, choose M here: the 600 572 module will be called w83697hf_wdt. 573 + 574 + Most people will say N. 575 + 576 + config W83697UG_WDT 577 + tristate "W83697UG/W83697UF Watchdog Timer" 578 + depends on X86 579 + ---help--- 580 + This is the driver for the hardware watchdog on the W83697UG/UF 581 + chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others). 582 + This watchdog simply watches your kernel to make sure it doesn't 583 + freeze, and if it does, it reboots your computer after a certain 584 + amount of time. 585 + 586 + To compile this driver as a module, choose M here: the 587 + module will be called w83697ug_wdt. 601 588 602 589 Most people will say N. 603 590
+4
drivers/watchdog/Makefile
··· 26 26 27 27 # ARM Architecture 28 28 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o 29 + obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o 29 30 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o 30 31 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o 31 32 obj-$(CONFIG_977_WATCHDOG) += wdt977.o ··· 40 39 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o 41 40 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o 42 41 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o 42 + obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o 43 43 44 44 # ARM26 Architecture 45 45 ··· 73 71 obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o 74 72 endif 75 73 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o 74 + obj-$(CONFIG_IT87_WDT) += it87_wdt.o 76 75 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o 77 76 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o 78 77 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o ··· 86 83 obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o 87 84 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o 88 85 obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o 86 + obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o 89 87 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o 90 88 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o 91 89 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+328
drivers/watchdog/at91sam9_wdt.c
··· 1 + /* 2 + * Watchdog driver for Atmel AT91SAM9x processors. 3 + * 4 + * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + /* 13 + * The Watchdog Timer Mode Register can be only written to once. If the 14 + * timeout need to be set from Linux, be sure that the bootstrap or the 15 + * bootloader doesn't write to this register. 16 + */ 17 + 18 + #include <linux/errno.h> 19 + #include <linux/fs.h> 20 + #include <linux/init.h> 21 + #include <linux/kernel.h> 22 + #include <linux/miscdevice.h> 23 + #include <linux/module.h> 24 + #include <linux/moduleparam.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/types.h> 27 + #include <linux/watchdog.h> 28 + #include <linux/jiffies.h> 29 + #include <linux/timer.h> 30 + #include <linux/bitops.h> 31 + #include <linux/uaccess.h> 32 + 33 + #include <asm/arch/at91_wdt.h> 34 + 35 + #define DRV_NAME "AT91SAM9 Watchdog" 36 + 37 + /* AT91SAM9 watchdog runs a 12bit counter @ 256Hz, 38 + * use this to convert a watchdog 39 + * value from/to milliseconds. 40 + */ 41 + #define ms_to_ticks(t) (((t << 8) / 1000) - 1) 42 + #define ticks_to_ms(t) (((t + 1) * 1000) >> 8) 43 + 44 + /* Hardware timeout in seconds */ 45 + #define WDT_HW_TIMEOUT 2 46 + 47 + /* Timer heartbeat (500ms) */ 48 + #define WDT_TIMEOUT (HZ/2) 49 + 50 + /* User land timeout */ 51 + #define WDT_HEARTBEAT 15 52 + static int heartbeat = WDT_HEARTBEAT; 53 + module_param(heartbeat, int, 0); 54 + MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. " 55 + "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")"); 56 + 57 + static int nowayout = WATCHDOG_NOWAYOUT; 58 + module_param(nowayout, int, 0); 59 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 60 + "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 61 + 62 + static void at91_ping(unsigned long data); 63 + 64 + static struct { 65 + unsigned long next_heartbeat; /* the next_heartbeat for the timer */ 66 + unsigned long open; 67 + char expect_close; 68 + struct timer_list timer; /* The timer that pings the watchdog */ 69 + } at91wdt_private; 70 + 71 + /* ......................................................................... */ 72 + 73 + 74 + /* 75 + * Reload the watchdog timer. (ie, pat the watchdog) 76 + */ 77 + static inline void at91_wdt_reset(void) 78 + { 79 + at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); 80 + } 81 + 82 + /* 83 + * Timer tick 84 + */ 85 + static void at91_ping(unsigned long data) 86 + { 87 + if (time_before(jiffies, at91wdt_private.next_heartbeat) || 88 + (!nowayout && !at91wdt_private.open)) { 89 + at91_wdt_reset(); 90 + mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 91 + } else 92 + printk(KERN_CRIT DRV_NAME": I will reset your machine !\n"); 93 + } 94 + 95 + /* 96 + * Watchdog device is opened, and watchdog starts running. 97 + */ 98 + static int at91_wdt_open(struct inode *inode, struct file *file) 99 + { 100 + if (test_and_set_bit(0, &at91wdt_private.open)) 101 + return -EBUSY; 102 + 103 + at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ; 104 + mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 105 + 106 + return nonseekable_open(inode, file); 107 + } 108 + 109 + /* 110 + * Close the watchdog device. 111 + */ 112 + static int at91_wdt_close(struct inode *inode, struct file *file) 113 + { 114 + clear_bit(0, &at91wdt_private.open); 115 + 116 + /* stop internal ping */ 117 + if (!at91wdt_private.expect_close) 118 + del_timer(&at91wdt_private.timer); 119 + 120 + at91wdt_private.expect_close = 0; 121 + return 0; 122 + } 123 + 124 + /* 125 + * Set the watchdog time interval in 1/256Hz (write-once) 126 + * Counter is 12 bit. 127 + */ 128 + static int at91_wdt_settimeout(unsigned int timeout) 129 + { 130 + unsigned int reg; 131 + unsigned int mr; 132 + 133 + /* Check if disabled */ 134 + mr = at91_sys_read(AT91_WDT_MR); 135 + if (mr & AT91_WDT_WDDIS) { 136 + printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n"); 137 + return -EIO; 138 + } 139 + 140 + /* 141 + * All counting occurs at SLOW_CLOCK / 128 = 256 Hz 142 + * 143 + * Since WDV is a 12-bit counter, the maximum period is 144 + * 4096 / 256 = 16 seconds. 145 + */ 146 + reg = AT91_WDT_WDRSTEN /* causes watchdog reset */ 147 + /* | AT91_WDT_WDRPROC causes processor reset only */ 148 + | AT91_WDT_WDDBGHLT /* disabled in debug mode */ 149 + | AT91_WDT_WDD /* restart at any time */ 150 + | (timeout & AT91_WDT_WDV); /* timer value */ 151 + at91_sys_write(AT91_WDT_MR, reg); 152 + 153 + return 0; 154 + } 155 + 156 + static const struct watchdog_info at91_wdt_info = { 157 + .identity = DRV_NAME, 158 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 159 + }; 160 + 161 + /* 162 + * Handle commands from user-space. 163 + */ 164 + static long at91_wdt_ioctl(struct file *file, 165 + unsigned int cmd, unsigned long arg) 166 + { 167 + void __user *argp = (void __user *)arg; 168 + int __user *p = argp; 169 + int new_value; 170 + 171 + switch (cmd) { 172 + case WDIOC_GETSUPPORT: 173 + return copy_to_user(argp, &at91_wdt_info, 174 + sizeof(at91_wdt_info)) ? -EFAULT : 0; 175 + 176 + case WDIOC_GETSTATUS: 177 + case WDIOC_GETBOOTSTATUS: 178 + return put_user(0, p); 179 + 180 + case WDIOC_KEEPALIVE: 181 + at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ; 182 + return 0; 183 + 184 + case WDIOC_SETTIMEOUT: 185 + if (get_user(new_value, p)) 186 + return -EFAULT; 187 + 188 + heartbeat = new_value; 189 + at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ; 190 + 191 + return put_user(new_value, p); /* return current value */ 192 + 193 + case WDIOC_GETTIMEOUT: 194 + return put_user(heartbeat, p); 195 + } 196 + return -ENOTTY; 197 + } 198 + 199 + /* 200 + * Pat the watchdog whenever device is written to. 201 + */ 202 + static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, 203 + loff_t *ppos) 204 + { 205 + if (!len) 206 + return 0; 207 + 208 + /* Scan for magic character */ 209 + if (!nowayout) { 210 + size_t i; 211 + 212 + at91wdt_private.expect_close = 0; 213 + 214 + for (i = 0; i < len; i++) { 215 + char c; 216 + if (get_user(c, data + i)) 217 + return -EFAULT; 218 + if (c == 'V') { 219 + at91wdt_private.expect_close = 42; 220 + break; 221 + } 222 + } 223 + } 224 + 225 + at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ; 226 + 227 + return len; 228 + } 229 + 230 + /* ......................................................................... */ 231 + 232 + static const struct file_operations at91wdt_fops = { 233 + .owner = THIS_MODULE, 234 + .llseek = no_llseek, 235 + .unlocked_ioctl = at91_wdt_ioctl, 236 + .open = at91_wdt_open, 237 + .release = at91_wdt_close, 238 + .write = at91_wdt_write, 239 + }; 240 + 241 + static struct miscdevice at91wdt_miscdev = { 242 + .minor = WATCHDOG_MINOR, 243 + .name = "watchdog", 244 + .fops = &at91wdt_fops, 245 + }; 246 + 247 + static int __init at91wdt_probe(struct platform_device *pdev) 248 + { 249 + int res; 250 + 251 + if (at91wdt_miscdev.parent) 252 + return -EBUSY; 253 + at91wdt_miscdev.parent = &pdev->dev; 254 + 255 + /* Set watchdog */ 256 + res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000)); 257 + if (res) 258 + return res; 259 + 260 + res = misc_register(&at91wdt_miscdev); 261 + if (res) 262 + return res; 263 + 264 + at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ; 265 + setup_timer(&at91wdt_private.timer, at91_ping, 0); 266 + mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 267 + 268 + printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n", 269 + heartbeat, nowayout); 270 + 271 + return 0; 272 + } 273 + 274 + static int __exit at91wdt_remove(struct platform_device *pdev) 275 + { 276 + int res; 277 + 278 + res = misc_deregister(&at91wdt_miscdev); 279 + if (!res) 280 + at91wdt_miscdev.parent = NULL; 281 + 282 + return res; 283 + } 284 + 285 + #ifdef CONFIG_PM 286 + 287 + static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message) 288 + { 289 + return 0; 290 + } 291 + 292 + static int at91wdt_resume(struct platform_device *pdev) 293 + { 294 + return 0; 295 + } 296 + 297 + #else 298 + #define at91wdt_suspend NULL 299 + #define at91wdt_resume NULL 300 + #endif 301 + 302 + static struct platform_driver at91wdt_driver = { 303 + .remove = __exit_p(at91wdt_remove), 304 + .suspend = at91wdt_suspend, 305 + .resume = at91wdt_resume, 306 + .driver = { 307 + .name = "at91_wdt", 308 + .owner = THIS_MODULE, 309 + }, 310 + }; 311 + 312 + static int __init at91sam_wdt_init(void) 313 + { 314 + return platform_driver_probe(&at91wdt_driver, at91wdt_probe); 315 + } 316 + 317 + static void __exit at91sam_wdt_exit(void) 318 + { 319 + platform_driver_unregister(&at91wdt_driver); 320 + } 321 + 322 + module_init(at91sam_wdt_init); 323 + module_exit(at91sam_wdt_exit); 324 + 325 + MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>"); 326 + MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors"); 327 + MODULE_LICENSE("GPL"); 328 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+725
drivers/watchdog/it87_wdt.c
··· 1 + /* 2 + * Watchdog Timer Driver 3 + * for ITE IT87xx Environment Control - Low Pin Count Input / Output 4 + * 5 + * (c) Copyright 2007 Oliver Schuster <olivers137@aol.com> 6 + * 7 + * Based on softdog.c by Alan Cox, 8 + * 83977f_wdt.c by Jose Goncalves, 9 + * it87.c by Chris Gauthron, Jean Delvare 10 + * 11 + * Data-sheets: Publicly available at the ITE website 12 + * http://www.ite.com.tw/ 13 + * 14 + * Support of the watchdog timers, which are available on 15 + * IT8716, IT8718, IT8726 and IT8712 (J,K version). 16 + * 17 + * This program is free software; you can redistribute it and/or 18 + * modify it under the terms of the GNU General Public License 19 + * as published by the Free Software Foundation; either version 20 + * 2 of the License, or (at your option) any later version. 21 + * 22 + * This program is distributed in the hope that it will be useful, 23 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 + * GNU General Public License for more details. 26 + * 27 + * You should have received a copy of the GNU General Public License 28 + * along with this program; if not, write to the Free Software 29 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 30 + */ 31 + 32 + #include <linux/module.h> 33 + #include <linux/moduleparam.h> 34 + #include <linux/types.h> 35 + #include <linux/kernel.h> 36 + #include <linux/fs.h> 37 + #include <linux/miscdevice.h> 38 + #include <linux/init.h> 39 + #include <linux/ioport.h> 40 + #include <linux/watchdog.h> 41 + #include <linux/notifier.h> 42 + #include <linux/reboot.h> 43 + #include <linux/uaccess.h> 44 + #include <linux/io.h> 45 + 46 + #include <asm/system.h> 47 + 48 + #define WATCHDOG_VERSION "1.12" 49 + #define WATCHDOG_NAME "IT87 WDT" 50 + #define PFX WATCHDOG_NAME ": " 51 + #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" 52 + #define WD_MAGIC 'V' 53 + 54 + /* Defaults for Module Parameter */ 55 + #define DEFAULT_NOGAMEPORT 0 56 + #define DEFAULT_EXCLUSIVE 1 57 + #define DEFAULT_TIMEOUT 60 58 + #define DEFAULT_TESTMODE 0 59 + #define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT 60 + 61 + /* IO Ports */ 62 + #define REG 0x2e 63 + #define VAL 0x2f 64 + 65 + /* Logical device Numbers LDN */ 66 + #define GPIO 0x07 67 + #define GAMEPORT 0x09 68 + #define CIR 0x0a 69 + 70 + /* Configuration Registers and Functions */ 71 + #define LDNREG 0x07 72 + #define CHIPID 0x20 73 + #define CHIPREV 0x22 74 + #define ACTREG 0x30 75 + #define BASEREG 0x60 76 + 77 + /* Chip Id numbers */ 78 + #define NO_DEV_ID 0xffff 79 + #define IT8705_ID 0x8705 80 + #define IT8712_ID 0x8712 81 + #define IT8716_ID 0x8716 82 + #define IT8718_ID 0x8718 83 + #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ 84 + 85 + /* GPIO Configuration Registers LDN=0x07 */ 86 + #define WDTCTRL 0x71 87 + #define WDTCFG 0x72 88 + #define WDTVALLSB 0x73 89 + #define WDTVALMSB 0x74 90 + 91 + /* GPIO Bits WDTCTRL */ 92 + #define WDT_CIRINT 0x80 93 + #define WDT_MOUSEINT 0x40 94 + #define WDT_KYBINT 0x20 95 + #define WDT_GAMEPORT 0x10 /* not it8718 */ 96 + #define WDT_FORCE 0x02 97 + #define WDT_ZERO 0x01 98 + 99 + /* GPIO Bits WDTCFG */ 100 + #define WDT_TOV1 0x80 101 + #define WDT_KRST 0x40 102 + #define WDT_TOVE 0x20 103 + #define WDT_PWROK 0x10 104 + #define WDT_INT_MASK 0x0f 105 + 106 + /* CIR Configuration Register LDN=0x0a */ 107 + #define CIR_ILS 0x70 108 + 109 + /* The default Base address is not always available, we use this */ 110 + #define CIR_BASE 0x0208 111 + 112 + /* CIR Controller */ 113 + #define CIR_DR(b) (b) 114 + #define CIR_IER(b) (b + 1) 115 + #define CIR_RCR(b) (b + 2) 116 + #define CIR_TCR1(b) (b + 3) 117 + #define CIR_TCR2(b) (b + 4) 118 + #define CIR_TSR(b) (b + 5) 119 + #define CIR_RSR(b) (b + 6) 120 + #define CIR_BDLR(b) (b + 5) 121 + #define CIR_BDHR(b) (b + 6) 122 + #define CIR_IIR(b) (b + 7) 123 + 124 + /* Default Base address of Game port */ 125 + #define GP_BASE_DEFAULT 0x0201 126 + 127 + /* wdt_status */ 128 + #define WDTS_TIMER_RUN 0 129 + #define WDTS_DEV_OPEN 1 130 + #define WDTS_KEEPALIVE 2 131 + #define WDTS_LOCKED 3 132 + #define WDTS_USE_GP 4 133 + #define WDTS_EXPECTED 5 134 + 135 + static unsigned int base, gpact, ciract; 136 + static unsigned long wdt_status; 137 + static DEFINE_SPINLOCK(spinlock); 138 + 139 + static int nogameport = DEFAULT_NOGAMEPORT; 140 + static int exclusive = DEFAULT_EXCLUSIVE; 141 + static int timeout = DEFAULT_TIMEOUT; 142 + static int testmode = DEFAULT_TESTMODE; 143 + static int nowayout = DEFAULT_NOWAYOUT; 144 + 145 + module_param(nogameport, int, 0); 146 + MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default=" 147 + __MODULE_STRING(DEFAULT_NOGAMEPORT)); 148 + module_param(exclusive, int, 0); 149 + MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default=" 150 + __MODULE_STRING(DEFAULT_EXCLUSIVE)); 151 + module_param(timeout, int, 0); 152 + MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default=" 153 + __MODULE_STRING(DEFAULT_TIMEOUT)); 154 + module_param(testmode, int, 0); 155 + MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default=" 156 + __MODULE_STRING(DEFAULT_TESTMODE)); 157 + module_param(nowayout, int, 0); 158 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default=" 159 + __MODULE_STRING(WATCHDOG_NOWAYOUT)); 160 + 161 + /* Superio Chip */ 162 + 163 + static inline void superio_enter(void) 164 + { 165 + outb(0x87, REG); 166 + outb(0x01, REG); 167 + outb(0x55, REG); 168 + outb(0x55, REG); 169 + } 170 + 171 + static inline void superio_exit(void) 172 + { 173 + outb(0x02, REG); 174 + outb(0x02, VAL); 175 + } 176 + 177 + static inline void superio_select(int ldn) 178 + { 179 + outb(LDNREG, REG); 180 + outb(ldn, VAL); 181 + } 182 + 183 + static inline int superio_inb(int reg) 184 + { 185 + outb(reg, REG); 186 + return inb(VAL); 187 + } 188 + 189 + static inline void superio_outb(int val, int reg) 190 + { 191 + outb(reg, REG); 192 + outb(val, VAL); 193 + } 194 + 195 + static inline int superio_inw(int reg) 196 + { 197 + int val; 198 + outb(reg++, REG); 199 + val = inb(VAL) << 8; 200 + outb(reg, REG); 201 + val |= inb(VAL); 202 + return val; 203 + } 204 + 205 + static inline void superio_outw(int val, int reg) 206 + { 207 + outb(reg++, REG); 208 + outb(val >> 8, VAL); 209 + outb(reg, REG); 210 + outb(val, VAL); 211 + } 212 + 213 + /* watchdog timer handling */ 214 + 215 + static void wdt_keepalive(void) 216 + { 217 + if (test_bit(WDTS_USE_GP, &wdt_status)) 218 + inb(base); 219 + else 220 + /* The timer reloads with around 5 msec delay */ 221 + outb(0x55, CIR_DR(base)); 222 + set_bit(WDTS_KEEPALIVE, &wdt_status); 223 + } 224 + 225 + static void wdt_start(void) 226 + { 227 + unsigned long flags; 228 + 229 + spin_lock_irqsave(&spinlock, flags); 230 + superio_enter(); 231 + 232 + superio_select(GPIO); 233 + if (test_bit(WDTS_USE_GP, &wdt_status)) 234 + superio_outb(WDT_GAMEPORT, WDTCTRL); 235 + else 236 + superio_outb(WDT_CIRINT, WDTCTRL); 237 + if (!testmode) 238 + superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG); 239 + else 240 + superio_outb(WDT_TOV1, WDTCFG); 241 + superio_outb(timeout>>8, WDTVALMSB); 242 + superio_outb(timeout, WDTVALLSB); 243 + 244 + superio_exit(); 245 + spin_unlock_irqrestore(&spinlock, flags); 246 + } 247 + 248 + static void wdt_stop(void) 249 + { 250 + unsigned long flags; 251 + 252 + spin_lock_irqsave(&spinlock, flags); 253 + superio_enter(); 254 + 255 + superio_select(GPIO); 256 + superio_outb(0x00, WDTCTRL); 257 + superio_outb(WDT_TOV1, WDTCFG); 258 + superio_outb(0x00, WDTVALMSB); 259 + superio_outb(0x00, WDTVALLSB); 260 + 261 + superio_exit(); 262 + spin_unlock_irqrestore(&spinlock, flags); 263 + } 264 + 265 + /** 266 + * wdt_set_timeout - set a new timeout value with watchdog ioctl 267 + * @t: timeout value in seconds 268 + * 269 + * The hardware device has a 16 bit watchdog timer, thus the 270 + * timeout time ranges between 1 and 65535 seconds. 271 + * 272 + * Used within WDIOC_SETTIMEOUT watchdog device ioctl. 273 + */ 274 + 275 + static int wdt_set_timeout(int t) 276 + { 277 + unsigned long flags; 278 + 279 + if (t < 1 || t > 65535) 280 + return -EINVAL; 281 + 282 + timeout = t; 283 + 284 + spin_lock_irqsave(&spinlock, flags); 285 + if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 286 + superio_enter(); 287 + 288 + superio_select(GPIO); 289 + superio_outb(t>>8, WDTVALMSB); 290 + superio_outb(t, WDTVALLSB); 291 + 292 + superio_exit(); 293 + } 294 + spin_unlock_irqrestore(&spinlock, flags); 295 + return 0; 296 + } 297 + 298 + /** 299 + * wdt_get_status - determines the status supported by watchdog ioctl 300 + * @status: status returned to user space 301 + * 302 + * The status bit of the device does not allow to distinguish 303 + * between a regular system reset and a watchdog forced reset. 304 + * But, in test mode it is useful, so it is supported through 305 + * WDIOC_GETSTATUS watchdog ioctl. Additionally the driver 306 + * reports the keepalive signal and the acception of the magic. 307 + * 308 + * Used within WDIOC_GETSTATUS watchdog device ioctl. 309 + */ 310 + 311 + static int wdt_get_status(int *status) 312 + { 313 + unsigned long flags; 314 + 315 + *status = 0; 316 + if (testmode) { 317 + spin_lock_irqsave(&spinlock, flags); 318 + superio_enter(); 319 + superio_select(GPIO); 320 + if (superio_inb(WDTCTRL) & WDT_ZERO) { 321 + superio_outb(0x00, WDTCTRL); 322 + clear_bit(WDTS_TIMER_RUN, &wdt_status); 323 + *status |= WDIOF_CARDRESET; 324 + } 325 + 326 + superio_exit(); 327 + spin_unlock_irqrestore(&spinlock, flags); 328 + } 329 + if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status)) 330 + *status |= WDIOF_KEEPALIVEPING; 331 + if (test_bit(WDTS_EXPECTED, &wdt_status)) 332 + *status |= WDIOF_MAGICCLOSE; 333 + return 0; 334 + } 335 + 336 + /* /dev/watchdog handling */ 337 + 338 + /** 339 + * wdt_open - watchdog file_operations .open 340 + * @inode: inode of the device 341 + * @file: file handle to the device 342 + * 343 + * The watchdog timer starts by opening the device. 344 + * 345 + * Used within the file operation of the watchdog device. 346 + */ 347 + 348 + static int wdt_open(struct inode *inode, struct file *file) 349 + { 350 + if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status)) 351 + return -EBUSY; 352 + if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { 353 + if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status)) 354 + __module_get(THIS_MODULE); 355 + wdt_start(); 356 + } 357 + return nonseekable_open(inode, file); 358 + } 359 + 360 + /** 361 + * wdt_release - watchdog file_operations .release 362 + * @inode: inode of the device 363 + * @file: file handle to the device 364 + * 365 + * Closing the watchdog device either stops the watchdog timer 366 + * or in the case, that nowayout is set or the magic character 367 + * wasn't written, a critical warning about an running watchdog 368 + * timer is given. 369 + * 370 + * Used within the file operation of the watchdog device. 371 + */ 372 + 373 + static int wdt_release(struct inode *inode, struct file *file) 374 + { 375 + if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 376 + if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) { 377 + wdt_stop(); 378 + clear_bit(WDTS_TIMER_RUN, &wdt_status); 379 + } else { 380 + wdt_keepalive(); 381 + printk(KERN_CRIT PFX 382 + "unexpected close, not stopping watchdog!\n"); 383 + } 384 + } 385 + clear_bit(WDTS_DEV_OPEN, &wdt_status); 386 + return 0; 387 + } 388 + 389 + /** 390 + * wdt_write - watchdog file_operations .write 391 + * @file: file handle to the watchdog 392 + * @buf: buffer to write 393 + * @count: count of bytes 394 + * @ppos: pointer to the position to write. No seeks allowed 395 + * 396 + * A write to a watchdog device is defined as a keepalive signal. Any 397 + * write of data will do, as we don't define content meaning. 398 + * 399 + * Used within the file operation of the watchdog device. 400 + */ 401 + 402 + static ssize_t wdt_write(struct file *file, const char __user *buf, 403 + size_t count, loff_t *ppos) 404 + { 405 + if (count) { 406 + clear_bit(WDTS_EXPECTED, &wdt_status); 407 + wdt_keepalive(); 408 + } 409 + if (!nowayout) { 410 + size_t ofs; 411 + 412 + /* note: just in case someone wrote the magic character long ago */ 413 + for (ofs = 0; ofs != count; ofs++) { 414 + char c; 415 + if (get_user(c, buf + ofs)) 416 + return -EFAULT; 417 + if (c == WD_MAGIC) 418 + set_bit(WDTS_EXPECTED, &wdt_status); 419 + } 420 + } 421 + return count; 422 + } 423 + 424 + static struct watchdog_info ident = { 425 + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 426 + .firmware_version = 1, 427 + .identity = WATCHDOG_NAME, 428 + }; 429 + 430 + /** 431 + * wdt_ioctl - watchdog file_operations .unlocked_ioctl 432 + * @file: file handle to the device 433 + * @cmd: watchdog command 434 + * @arg: argument pointer 435 + * 436 + * The watchdog API defines a common set of functions for all watchdogs 437 + * according to their available features. 438 + * 439 + * Used within the file operation of the watchdog device. 440 + */ 441 + 442 + static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 443 + { 444 + int rc = 0, status, new_options, new_timeout; 445 + union { 446 + struct watchdog_info __user *ident; 447 + int __user *i; 448 + } uarg; 449 + 450 + uarg.i = (int __user *)arg; 451 + 452 + switch (cmd) { 453 + case WDIOC_GETSUPPORT: 454 + return copy_to_user(uarg.ident, 455 + &ident, sizeof(ident)) ? -EFAULT : 0; 456 + 457 + case WDIOC_GETSTATUS: 458 + wdt_get_status(&status); 459 + return put_user(status, uarg.i); 460 + 461 + case WDIOC_GETBOOTSTATUS: 462 + return put_user(0, uarg.i); 463 + 464 + case WDIOC_KEEPALIVE: 465 + wdt_keepalive(); 466 + return 0; 467 + 468 + case WDIOC_SETOPTIONS: 469 + if (get_user(new_options, uarg.i)) 470 + return -EFAULT; 471 + 472 + switch (new_options) { 473 + case WDIOS_DISABLECARD: 474 + if (test_bit(WDTS_TIMER_RUN, &wdt_status)) 475 + wdt_stop(); 476 + clear_bit(WDTS_TIMER_RUN, &wdt_status); 477 + return 0; 478 + 479 + case WDIOS_ENABLECARD: 480 + if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) 481 + wdt_start(); 482 + return 0; 483 + 484 + default: 485 + return -EFAULT; 486 + } 487 + 488 + case WDIOC_SETTIMEOUT: 489 + if (get_user(new_timeout, uarg.i)) 490 + return -EFAULT; 491 + rc = wdt_set_timeout(new_timeout); 492 + case WDIOC_GETTIMEOUT: 493 + if (put_user(timeout, uarg.i)) 494 + return -EFAULT; 495 + return rc; 496 + 497 + default: 498 + return -ENOTTY; 499 + } 500 + } 501 + 502 + static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 503 + void *unused) 504 + { 505 + if (code == SYS_DOWN || code == SYS_HALT) 506 + wdt_stop(); 507 + return NOTIFY_DONE; 508 + } 509 + 510 + static const struct file_operations wdt_fops = { 511 + .owner = THIS_MODULE, 512 + .llseek = no_llseek, 513 + .write = wdt_write, 514 + .unlocked_ioctl = wdt_ioctl, 515 + .open = wdt_open, 516 + .release = wdt_release, 517 + }; 518 + 519 + static struct miscdevice wdt_miscdev = { 520 + .minor = WATCHDOG_MINOR, 521 + .name = "watchdog", 522 + .fops = &wdt_fops, 523 + }; 524 + 525 + static struct notifier_block wdt_notifier = { 526 + .notifier_call = wdt_notify_sys, 527 + }; 528 + 529 + static int __init it87_wdt_init(void) 530 + { 531 + int rc = 0; 532 + u16 chip_type; 533 + u8 chip_rev; 534 + unsigned long flags; 535 + 536 + spin_lock_irqsave(&spinlock, flags); 537 + superio_enter(); 538 + chip_type = superio_inw(CHIPID); 539 + chip_rev = superio_inb(CHIPREV) & 0x0f; 540 + superio_exit(); 541 + spin_unlock_irqrestore(&spinlock, flags); 542 + 543 + switch (chip_type) { 544 + case IT8716_ID: 545 + case IT8718_ID: 546 + case IT8726_ID: 547 + break; 548 + case IT8712_ID: 549 + if (chip_rev > 7) 550 + break; 551 + case IT8705_ID: 552 + printk(KERN_ERR PFX 553 + "Unsupported Chip found, Chip %04x Revision %02x\n", 554 + chip_type, chip_rev); 555 + return -ENODEV; 556 + case NO_DEV_ID: 557 + printk(KERN_ERR PFX "no device\n"); 558 + return -ENODEV; 559 + default: 560 + printk(KERN_ERR PFX 561 + "Unknown Chip found, Chip %04x Revision %04x\n", 562 + chip_type, chip_rev); 563 + return -ENODEV; 564 + } 565 + 566 + spin_lock_irqsave(&spinlock, flags); 567 + superio_enter(); 568 + 569 + superio_select(GPIO); 570 + superio_outb(WDT_TOV1, WDTCFG); 571 + superio_outb(0x00, WDTCTRL); 572 + 573 + /* First try to get Gameport support */ 574 + if (chip_type != IT8718_ID && !nogameport) { 575 + superio_select(GAMEPORT); 576 + base = superio_inw(BASEREG); 577 + if (!base) { 578 + base = GP_BASE_DEFAULT; 579 + superio_outw(base, BASEREG); 580 + } 581 + gpact = superio_inb(ACTREG); 582 + superio_outb(0x01, ACTREG); 583 + superio_exit(); 584 + spin_unlock_irqrestore(&spinlock, flags); 585 + if (request_region(base, 1, WATCHDOG_NAME)) 586 + set_bit(WDTS_USE_GP, &wdt_status); 587 + else 588 + rc = -EIO; 589 + } else { 590 + superio_exit(); 591 + spin_unlock_irqrestore(&spinlock, flags); 592 + } 593 + 594 + /* If we haven't Gameport support, try to get CIR support */ 595 + if (!test_bit(WDTS_USE_GP, &wdt_status)) { 596 + if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { 597 + if (rc == -EIO) 598 + printk(KERN_ERR PFX 599 + "I/O Address 0x%04x and 0x%04x" 600 + " already in use\n", base, CIR_BASE); 601 + else 602 + printk(KERN_ERR PFX 603 + "I/O Address 0x%04x already in use\n", 604 + CIR_BASE); 605 + rc = -EIO; 606 + goto err_out; 607 + } 608 + base = CIR_BASE; 609 + spin_lock_irqsave(&spinlock, flags); 610 + superio_enter(); 611 + 612 + superio_select(CIR); 613 + superio_outw(base, BASEREG); 614 + superio_outb(0x00, CIR_ILS); 615 + ciract = superio_inb(ACTREG); 616 + superio_outb(0x01, ACTREG); 617 + if (rc == -EIO) { 618 + superio_select(GAMEPORT); 619 + superio_outb(gpact, ACTREG); 620 + } 621 + 622 + superio_exit(); 623 + spin_unlock_irqrestore(&spinlock, flags); 624 + } 625 + 626 + if (timeout < 1 || timeout > 65535) { 627 + timeout = DEFAULT_TIMEOUT; 628 + printk(KERN_WARNING PFX 629 + "Timeout value out of range, use default %d sec\n", 630 + DEFAULT_TIMEOUT); 631 + } 632 + 633 + rc = register_reboot_notifier(&wdt_notifier); 634 + if (rc) { 635 + printk(KERN_ERR PFX 636 + "Cannot register reboot notifier (err=%d)\n", rc); 637 + goto err_out_region; 638 + } 639 + 640 + rc = misc_register(&wdt_miscdev); 641 + if (rc) { 642 + printk(KERN_ERR PFX 643 + "Cannot register miscdev on minor=%d (err=%d)\n", 644 + wdt_miscdev.minor, rc); 645 + goto err_out_reboot; 646 + } 647 + 648 + /* Initialize CIR to use it as keepalive source */ 649 + if (!test_bit(WDTS_USE_GP, &wdt_status)) { 650 + outb(0x00, CIR_RCR(base)); 651 + outb(0xc0, CIR_TCR1(base)); 652 + outb(0x5c, CIR_TCR2(base)); 653 + outb(0x10, CIR_IER(base)); 654 + outb(0x00, CIR_BDHR(base)); 655 + outb(0x01, CIR_BDLR(base)); 656 + outb(0x09, CIR_IER(base)); 657 + } 658 + 659 + printk(KERN_INFO PFX "Chip it%04x revision %d initialized. " 660 + "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d " 661 + "nogameport=%d)\n", chip_type, chip_rev, timeout, 662 + nowayout, testmode, exclusive, nogameport); 663 + 664 + return 0; 665 + 666 + err_out_reboot: 667 + unregister_reboot_notifier(&wdt_notifier); 668 + err_out_region: 669 + release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 670 + if (!test_bit(WDTS_USE_GP, &wdt_status)) { 671 + spin_lock_irqsave(&spinlock, flags); 672 + superio_enter(); 673 + superio_select(CIR); 674 + superio_outb(ciract, ACTREG); 675 + superio_exit(); 676 + spin_unlock_irqrestore(&spinlock, flags); 677 + } 678 + err_out: 679 + if (chip_type != IT8718_ID && !nogameport) { 680 + spin_lock_irqsave(&spinlock, flags); 681 + superio_enter(); 682 + superio_select(GAMEPORT); 683 + superio_outb(gpact, ACTREG); 684 + superio_exit(); 685 + spin_unlock_irqrestore(&spinlock, flags); 686 + } 687 + 688 + return rc; 689 + } 690 + 691 + static void __exit it87_wdt_exit(void) 692 + { 693 + unsigned long flags; 694 + int nolock; 695 + 696 + nolock = !spin_trylock_irqsave(&spinlock, flags); 697 + superio_enter(); 698 + superio_select(GPIO); 699 + superio_outb(0x00, WDTCTRL); 700 + superio_outb(0x00, WDTCFG); 701 + superio_outb(0x00, WDTVALMSB); 702 + superio_outb(0x00, WDTVALLSB); 703 + if (test_bit(WDTS_USE_GP, &wdt_status)) { 704 + superio_select(GAMEPORT); 705 + superio_outb(gpact, ACTREG); 706 + } else { 707 + superio_select(CIR); 708 + superio_outb(ciract, ACTREG); 709 + } 710 + superio_exit(); 711 + if (!nolock) 712 + spin_unlock_irqrestore(&spinlock, flags); 713 + 714 + misc_deregister(&wdt_miscdev); 715 + unregister_reboot_notifier(&wdt_notifier); 716 + release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 717 + } 718 + 719 + module_init(it87_wdt_init); 720 + module_exit(it87_wdt_exit); 721 + 722 + MODULE_AUTHOR("Oliver Schuster"); 723 + MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O"); 724 + MODULE_LICENSE("GPL"); 725 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+226 -115
drivers/watchdog/omap_wdt.c
··· 1 1 /* 2 - * linux/drivers/char/watchdog/omap_wdt.c 2 + * omap_wdt.c 3 3 * 4 - * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog 4 + * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog 5 5 * 6 6 * Author: MontaVista Software, Inc. 7 7 * <gdavis@mvista.com> or <source@mvista.com> ··· 47 47 48 48 #include "omap_wdt.h" 49 49 50 + static struct platform_device *omap_wdt_dev; 51 + 50 52 static unsigned timer_margin; 51 53 module_param(timer_margin, uint, 0); 52 54 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); 53 55 54 - static int omap_wdt_users; 55 - static struct clk *armwdt_ck; 56 - static struct clk *mpu_wdt_ick; 57 - static struct clk *mpu_wdt_fck; 58 - 59 56 static unsigned int wdt_trgr_pattern = 0x1234; 60 57 static spinlock_t wdt_lock; 61 58 62 - static void omap_wdt_ping(void) 59 + struct omap_wdt_dev { 60 + void __iomem *base; /* physical */ 61 + struct device *dev; 62 + int omap_wdt_users; 63 + struct clk *armwdt_ck; 64 + struct clk *mpu_wdt_ick; 65 + struct clk *mpu_wdt_fck; 66 + struct resource *mem; 67 + struct miscdevice omap_wdt_miscdev; 68 + }; 69 + 70 + static void omap_wdt_ping(struct omap_wdt_dev *wdev) 63 71 { 72 + void __iomem *base = wdev->base; 73 + 64 74 /* wait for posted write to complete */ 65 - while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) 75 + while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 66 76 cpu_relax(); 77 + 67 78 wdt_trgr_pattern = ~wdt_trgr_pattern; 68 - omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR)); 79 + __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR)); 80 + 69 81 /* wait for posted write to complete */ 70 - while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) 82 + while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 71 83 cpu_relax(); 72 84 /* reloaded WCRR from WLDR */ 73 85 } 74 86 75 - static void omap_wdt_enable(void) 87 + static void omap_wdt_enable(struct omap_wdt_dev *wdev) 76 88 { 89 + void __iomem *base = wdev->base; 90 + 77 91 /* Sequence to enable the watchdog */ 78 - omap_writel(0xBBBB, OMAP_WATCHDOG_SPR); 79 - while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) 92 + __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR); 93 + while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10) 80 94 cpu_relax(); 81 - omap_writel(0x4444, OMAP_WATCHDOG_SPR); 82 - while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) 95 + 96 + __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR); 97 + while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10) 83 98 cpu_relax(); 84 99 } 85 100 86 - static void omap_wdt_disable(void) 101 + static void omap_wdt_disable(struct omap_wdt_dev *wdev) 87 102 { 103 + void __iomem *base = wdev->base; 104 + 88 105 /* sequence required to disable watchdog */ 89 - omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ 90 - while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) 106 + __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */ 107 + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10) 91 108 cpu_relax(); 92 - omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ 93 - while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) 109 + 110 + __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */ 111 + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10) 94 112 cpu_relax(); 95 113 } 96 114 ··· 121 103 timer_margin = new_timeout; 122 104 } 123 105 124 - static void omap_wdt_set_timeout(void) 106 + static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) 125 107 { 126 108 u32 pre_margin = GET_WLDR_VAL(timer_margin); 109 + void __iomem *base = wdev->base; 127 110 128 111 /* just count up at 32 KHz */ 129 - while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) 112 + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) 130 113 cpu_relax(); 131 - omap_writel(pre_margin, OMAP_WATCHDOG_LDR); 132 - while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) 114 + 115 + __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR); 116 + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) 133 117 cpu_relax(); 134 118 } 135 119 136 120 /* 137 121 * Allow only one task to hold it open 138 122 */ 139 - 140 123 static int omap_wdt_open(struct inode *inode, struct file *file) 141 124 { 142 - if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users)) 125 + struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev); 126 + void __iomem *base = wdev->base; 127 + 128 + if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users))) 143 129 return -EBUSY; 144 130 145 131 if (cpu_is_omap16xx()) 146 - clk_enable(armwdt_ck); /* Enable the clock */ 132 + clk_enable(wdev->armwdt_ck); /* Enable the clock */ 147 133 148 - if (cpu_is_omap24xx()) { 149 - clk_enable(mpu_wdt_ick); /* Enable the interface clock */ 150 - clk_enable(mpu_wdt_fck); /* Enable the functional clock */ 134 + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { 135 + clk_enable(wdev->mpu_wdt_ick); /* Enable the interface clock */ 136 + clk_enable(wdev->mpu_wdt_fck); /* Enable the functional clock */ 151 137 } 152 138 153 139 /* initialize prescaler */ 154 - while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) 155 - cpu_relax(); 156 - omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL); 157 - while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) 140 + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) 158 141 cpu_relax(); 159 142 160 - omap_wdt_set_timeout(); 161 - omap_wdt_enable(); 143 + __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL); 144 + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) 145 + cpu_relax(); 146 + 147 + file->private_data = (void *) wdev; 148 + 149 + omap_wdt_set_timeout(wdev); 150 + omap_wdt_enable(wdev); 151 + 162 152 return nonseekable_open(inode, file); 163 153 } 164 154 165 155 static int omap_wdt_release(struct inode *inode, struct file *file) 166 156 { 157 + struct omap_wdt_dev *wdev = file->private_data; 158 + 167 159 /* 168 160 * Shut off the timer unless NOWAYOUT is defined. 169 161 */ 170 162 #ifndef CONFIG_WATCHDOG_NOWAYOUT 171 - omap_wdt_disable(); 172 163 173 - if (cpu_is_omap16xx()) { 174 - clk_disable(armwdt_ck); /* Disable the clock */ 175 - clk_put(armwdt_ck); 176 - armwdt_ck = NULL; 177 - } 164 + omap_wdt_disable(wdev); 178 165 179 - if (cpu_is_omap24xx()) { 180 - clk_disable(mpu_wdt_ick); /* Disable the clock */ 181 - clk_disable(mpu_wdt_fck); /* Disable the clock */ 182 - clk_put(mpu_wdt_ick); 183 - clk_put(mpu_wdt_fck); 184 - mpu_wdt_ick = NULL; 185 - mpu_wdt_fck = NULL; 166 + if (cpu_is_omap16xx()) 167 + clk_disable(wdev->armwdt_ck); /* Disable the clock */ 168 + 169 + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { 170 + clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */ 171 + clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */ 186 172 } 187 173 #else 188 174 printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); 189 175 #endif 190 - omap_wdt_users = 0; 176 + wdev->omap_wdt_users = 0; 177 + 191 178 return 0; 192 179 } 193 180 194 181 static ssize_t omap_wdt_write(struct file *file, const char __user *data, 195 182 size_t len, loff_t *ppos) 196 183 { 184 + struct omap_wdt_dev *wdev = file->private_data; 185 + 197 186 /* Refresh LOAD_TIME. */ 198 187 if (len) { 199 188 spin_lock(&wdt_lock); 200 - omap_wdt_ping(); 189 + omap_wdt_ping(wdev); 201 190 spin_unlock(&wdt_lock); 202 191 } 203 192 return len; ··· 213 188 static long omap_wdt_ioctl(struct file *file, unsigned int cmd, 214 189 unsigned long arg) 215 190 { 191 + struct omap_wdt_dev *wdev; 216 192 int new_margin; 217 193 static const struct watchdog_info ident = { 218 194 .identity = "OMAP Watchdog", 219 195 .options = WDIOF_SETTIMEOUT, 220 196 .firmware_version = 0, 221 197 }; 198 + 199 + wdev = file->private_data; 222 200 223 201 switch (cmd) { 224 202 case WDIOC_GETSUPPORT: ··· 231 203 return put_user(0, (int __user *)arg); 232 204 case WDIOC_GETBOOTSTATUS: 233 205 if (cpu_is_omap16xx()) 234 - return put_user(omap_readw(ARM_SYSST), 206 + return put_user(__raw_readw(ARM_SYSST), 235 207 (int __user *)arg); 236 208 if (cpu_is_omap24xx()) 237 209 return put_user(omap_prcm_get_reset_sources(), 238 210 (int __user *)arg); 239 211 case WDIOC_KEEPALIVE: 240 212 spin_lock(&wdt_lock); 241 - omap_wdt_ping(); 213 + omap_wdt_ping(wdev); 242 214 spin_unlock(&wdt_lock); 243 215 return 0; 244 216 case WDIOC_SETTIMEOUT: ··· 247 219 omap_wdt_adjust_timeout(new_margin); 248 220 249 221 spin_lock(&wdt_lock); 250 - omap_wdt_disable(); 251 - omap_wdt_set_timeout(); 252 - omap_wdt_enable(); 222 + omap_wdt_disable(wdev); 223 + omap_wdt_set_timeout(wdev); 224 + omap_wdt_enable(wdev); 253 225 254 - omap_wdt_ping(); 226 + omap_wdt_ping(wdev); 255 227 spin_unlock(&wdt_lock); 256 228 /* Fall */ 257 229 case WDIOC_GETTIMEOUT: ··· 269 241 .release = omap_wdt_release, 270 242 }; 271 243 272 - static struct miscdevice omap_wdt_miscdev = { 273 - .minor = WATCHDOG_MINOR, 274 - .name = "watchdog", 275 - .fops = &omap_wdt_fops, 276 - }; 277 - 278 244 static int __init omap_wdt_probe(struct platform_device *pdev) 279 245 { 280 246 struct resource *res, *mem; 247 + struct omap_wdt_dev *wdev; 281 248 int ret; 282 249 283 250 /* reserve static register mappings */ 284 251 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 285 - if (!res) 286 - return -ENOENT; 252 + if (!res) { 253 + ret = -ENOENT; 254 + goto err_get_resource; 255 + } 256 + 257 + if (omap_wdt_dev) { 258 + ret = -EBUSY; 259 + goto err_busy; 260 + } 287 261 288 262 mem = request_mem_region(res->start, res->end - res->start + 1, 289 263 pdev->name); 290 - if (mem == NULL) 291 - return -EBUSY; 264 + if (!mem) { 265 + ret = -EBUSY; 266 + goto err_busy; 267 + } 292 268 293 - platform_set_drvdata(pdev, mem); 269 + wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); 270 + if (!wdev) { 271 + ret = -ENOMEM; 272 + goto err_kzalloc; 273 + } 294 274 295 - omap_wdt_users = 0; 275 + wdev->omap_wdt_users = 0; 276 + wdev->mem = mem; 296 277 297 278 if (cpu_is_omap16xx()) { 298 - armwdt_ck = clk_get(&pdev->dev, "armwdt_ck"); 299 - if (IS_ERR(armwdt_ck)) { 300 - ret = PTR_ERR(armwdt_ck); 301 - armwdt_ck = NULL; 302 - goto fail; 279 + wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck"); 280 + if (IS_ERR(wdev->armwdt_ck)) { 281 + ret = PTR_ERR(wdev->armwdt_ck); 282 + wdev->armwdt_ck = NULL; 283 + goto err_clk; 303 284 } 304 285 } 305 286 306 287 if (cpu_is_omap24xx()) { 307 - mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick"); 308 - if (IS_ERR(mpu_wdt_ick)) { 309 - ret = PTR_ERR(mpu_wdt_ick); 310 - mpu_wdt_ick = NULL; 311 - goto fail; 288 + wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick"); 289 + if (IS_ERR(wdev->mpu_wdt_ick)) { 290 + ret = PTR_ERR(wdev->mpu_wdt_ick); 291 + wdev->mpu_wdt_ick = NULL; 292 + goto err_clk; 312 293 } 313 - mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck"); 314 - if (IS_ERR(mpu_wdt_fck)) { 315 - ret = PTR_ERR(mpu_wdt_fck); 316 - mpu_wdt_fck = NULL; 317 - goto fail; 294 + wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck"); 295 + if (IS_ERR(wdev->mpu_wdt_fck)) { 296 + ret = PTR_ERR(wdev->mpu_wdt_fck); 297 + wdev->mpu_wdt_fck = NULL; 298 + goto err_clk; 318 299 } 319 300 } 320 301 321 - omap_wdt_disable(); 302 + if (cpu_is_omap34xx()) { 303 + wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick"); 304 + if (IS_ERR(wdev->mpu_wdt_ick)) { 305 + ret = PTR_ERR(wdev->mpu_wdt_ick); 306 + wdev->mpu_wdt_ick = NULL; 307 + goto err_clk; 308 + } 309 + wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck"); 310 + if (IS_ERR(wdev->mpu_wdt_fck)) { 311 + ret = PTR_ERR(wdev->mpu_wdt_fck); 312 + wdev->mpu_wdt_fck = NULL; 313 + goto err_clk; 314 + } 315 + } 316 + wdev->base = ioremap(res->start, res->end - res->start + 1); 317 + if (!wdev->base) { 318 + ret = -ENOMEM; 319 + goto err_ioremap; 320 + } 321 + 322 + platform_set_drvdata(pdev, wdev); 323 + 324 + omap_wdt_disable(wdev); 322 325 omap_wdt_adjust_timeout(timer_margin); 323 326 324 - omap_wdt_miscdev.parent = &pdev->dev; 325 - ret = misc_register(&omap_wdt_miscdev); 326 - if (ret) 327 - goto fail; 327 + wdev->omap_wdt_miscdev.parent = &pdev->dev; 328 + wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR; 329 + wdev->omap_wdt_miscdev.name = "watchdog"; 330 + wdev->omap_wdt_miscdev.fops = &omap_wdt_fops; 328 331 329 - pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin); 332 + ret = misc_register(&(wdev->omap_wdt_miscdev)); 333 + if (ret) 334 + goto err_misc; 335 + 336 + pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", 337 + __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, 338 + timer_margin); 330 339 331 340 /* autogate OCP interface clock */ 332 - omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG); 341 + __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG); 342 + 343 + omap_wdt_dev = pdev; 344 + 333 345 return 0; 334 346 335 - fail: 336 - if (armwdt_ck) 337 - clk_put(armwdt_ck); 338 - if (mpu_wdt_ick) 339 - clk_put(mpu_wdt_ick); 340 - if (mpu_wdt_fck) 341 - clk_put(mpu_wdt_fck); 342 - release_resource(mem); 347 + err_misc: 348 + platform_set_drvdata(pdev, NULL); 349 + iounmap(wdev->base); 350 + 351 + err_ioremap: 352 + wdev->base = NULL; 353 + 354 + err_clk: 355 + if (wdev->armwdt_ck) 356 + clk_put(wdev->armwdt_ck); 357 + if (wdev->mpu_wdt_ick) 358 + clk_put(wdev->mpu_wdt_ick); 359 + if (wdev->mpu_wdt_fck) 360 + clk_put(wdev->mpu_wdt_fck); 361 + kfree(wdev); 362 + 363 + err_kzalloc: 364 + release_mem_region(res->start, res->end - res->start + 1); 365 + 366 + err_busy: 367 + err_get_resource: 368 + 343 369 return ret; 344 370 } 345 371 346 372 static void omap_wdt_shutdown(struct platform_device *pdev) 347 373 { 348 - omap_wdt_disable(); 374 + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 375 + 376 + if (wdev->omap_wdt_users) 377 + omap_wdt_disable(wdev); 349 378 } 350 379 351 380 static int omap_wdt_remove(struct platform_device *pdev) 352 381 { 353 - struct resource *mem = platform_get_drvdata(pdev); 354 - misc_deregister(&omap_wdt_miscdev); 355 - release_resource(mem); 356 - if (armwdt_ck) 357 - clk_put(armwdt_ck); 358 - if (mpu_wdt_ick) 359 - clk_put(mpu_wdt_ick); 360 - if (mpu_wdt_fck) 361 - clk_put(mpu_wdt_fck); 382 + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 383 + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 384 + 385 + if (!res) 386 + return -ENOENT; 387 + 388 + misc_deregister(&(wdev->omap_wdt_miscdev)); 389 + release_mem_region(res->start, res->end - res->start + 1); 390 + platform_set_drvdata(pdev, NULL); 391 + 392 + if (wdev->armwdt_ck) { 393 + clk_put(wdev->armwdt_ck); 394 + wdev->armwdt_ck = NULL; 395 + } 396 + 397 + if (wdev->mpu_wdt_ick) { 398 + clk_put(wdev->mpu_wdt_ick); 399 + wdev->mpu_wdt_ick = NULL; 400 + } 401 + 402 + if (wdev->mpu_wdt_fck) { 403 + clk_put(wdev->mpu_wdt_fck); 404 + wdev->mpu_wdt_fck = NULL; 405 + } 406 + iounmap(wdev->base); 407 + 408 + kfree(wdev); 409 + omap_wdt_dev = NULL; 410 + 362 411 return 0; 363 412 } 364 413 ··· 449 344 450 345 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) 451 346 { 452 - if (omap_wdt_users) 453 - omap_wdt_disable(); 347 + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 348 + 349 + if (wdev->omap_wdt_users) 350 + omap_wdt_disable(wdev); 351 + 454 352 return 0; 455 353 } 456 354 457 355 static int omap_wdt_resume(struct platform_device *pdev) 458 356 { 459 - if (omap_wdt_users) { 460 - omap_wdt_enable(); 461 - omap_wdt_ping(); 357 + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 358 + 359 + if (wdev->omap_wdt_users) { 360 + omap_wdt_enable(wdev); 361 + omap_wdt_ping(wdev); 462 362 } 363 + 463 364 return 0; 464 365 } 465 366
+9 -19
drivers/watchdog/omap_wdt.h
··· 30 30 #ifndef _OMAP_WATCHDOG_H 31 31 #define _OMAP_WATCHDOG_H 32 32 33 - #define OMAP1610_WATCHDOG_BASE 0xfffeb000 34 - #define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */ 35 - 36 - #ifdef CONFIG_ARCH_OMAP24XX 37 - #define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE 38 - #else 39 - #define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE 40 - #define RM_RSTST_WKUP 0 41 - #endif 42 - 43 - #define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00) 44 - #define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10) 45 - #define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14) 46 - #define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24) 47 - #define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28) 48 - #define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c) 49 - #define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30) 50 - #define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34) 51 - #define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48) 33 + #define OMAP_WATCHDOG_REV (0x00) 34 + #define OMAP_WATCHDOG_SYS_CONFIG (0x10) 35 + #define OMAP_WATCHDOG_STATUS (0x14) 36 + #define OMAP_WATCHDOG_CNTRL (0x24) 37 + #define OMAP_WATCHDOG_CRR (0x28) 38 + #define OMAP_WATCHDOG_LDR (0x2c) 39 + #define OMAP_WATCHDOG_TGR (0x30) 40 + #define OMAP_WATCHDOG_WPS (0x34) 41 + #define OMAP_WATCHDOG_SPR (0x48) 52 42 53 43 /* Using the prescaler, the OMAP watchdog could go for many 54 44 * months before firing. These limits work without scaling,
+245
drivers/watchdog/orion5x_wdt.c
··· 1 + /* 2 + * drivers/watchdog/orion5x_wdt.c 3 + * 4 + * Watchdog driver for Orion5x processors 5 + * 6 + * Author: Sylver Bruneau <sylver.bruneau@googlemail.com> 7 + * 8 + * This file is licensed under the terms of the GNU General Public 9 + * License version 2. This program is licensed "as is" without any 10 + * warranty of any kind, whether express or implied. 11 + */ 12 + 13 + #include <linux/module.h> 14 + #include <linux/moduleparam.h> 15 + #include <linux/types.h> 16 + #include <linux/kernel.h> 17 + #include <linux/fs.h> 18 + #include <linux/miscdevice.h> 19 + #include <linux/watchdog.h> 20 + #include <linux/init.h> 21 + #include <linux/uaccess.h> 22 + #include <linux/io.h> 23 + #include <linux/spinlock.h> 24 + 25 + /* 26 + * Watchdog timer block registers. 27 + */ 28 + #define TIMER_CTRL (TIMER_VIRT_BASE + 0x0000) 29 + #define WDT_EN 0x0010 30 + #define WDT_VAL (TIMER_VIRT_BASE + 0x0024) 31 + 32 + #define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK) 33 + #define WDT_IN_USE 0 34 + #define WDT_OK_TO_CLOSE 1 35 + 36 + static int nowayout = WATCHDOG_NOWAYOUT; 37 + static int heartbeat = WDT_MAX_DURATION; /* (seconds) */ 38 + static unsigned long wdt_status; 39 + static spinlock_t wdt_lock; 40 + 41 + static void wdt_enable(void) 42 + { 43 + u32 reg; 44 + 45 + spin_lock(&wdt_lock); 46 + 47 + /* Set watchdog duration */ 48 + writel(ORION5X_TCLK * heartbeat, WDT_VAL); 49 + 50 + /* Clear watchdog timer interrupt */ 51 + reg = readl(BRIDGE_CAUSE); 52 + reg &= ~WDT_INT_REQ; 53 + writel(reg, BRIDGE_CAUSE); 54 + 55 + /* Enable watchdog timer */ 56 + reg = readl(TIMER_CTRL); 57 + reg |= WDT_EN; 58 + writel(reg, TIMER_CTRL); 59 + 60 + /* Enable reset on watchdog */ 61 + reg = readl(CPU_RESET_MASK); 62 + reg |= WDT_RESET; 63 + writel(reg, CPU_RESET_MASK); 64 + 65 + spin_unlock(&wdt_lock); 66 + } 67 + 68 + static void wdt_disable(void) 69 + { 70 + u32 reg; 71 + 72 + spin_lock(&wdt_lock); 73 + 74 + /* Disable reset on watchdog */ 75 + reg = readl(CPU_RESET_MASK); 76 + reg &= ~WDT_RESET; 77 + writel(reg, CPU_RESET_MASK); 78 + 79 + /* Disable watchdog timer */ 80 + reg = readl(TIMER_CTRL); 81 + reg &= ~WDT_EN; 82 + writel(reg, TIMER_CTRL); 83 + 84 + spin_unlock(&wdt_lock); 85 + } 86 + 87 + static int orion5x_wdt_get_timeleft(int *time_left) 88 + { 89 + spin_lock(&wdt_lock); 90 + *time_left = readl(WDT_VAL) / ORION5X_TCLK; 91 + spin_unlock(&wdt_lock); 92 + return 0; 93 + } 94 + 95 + static int orion5x_wdt_open(struct inode *inode, struct file *file) 96 + { 97 + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) 98 + return -EBUSY; 99 + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); 100 + wdt_enable(); 101 + return nonseekable_open(inode, file); 102 + } 103 + 104 + static ssize_t orion5x_wdt_write(struct file *file, const char *data, 105 + size_t len, loff_t *ppos) 106 + { 107 + if (len) { 108 + if (!nowayout) { 109 + size_t i; 110 + 111 + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); 112 + for (i = 0; i != len; i++) { 113 + char c; 114 + 115 + if (get_user(c, data + i)) 116 + return -EFAULT; 117 + if (c == 'V') 118 + set_bit(WDT_OK_TO_CLOSE, &wdt_status); 119 + } 120 + } 121 + wdt_enable(); 122 + } 123 + return len; 124 + } 125 + 126 + static struct watchdog_info ident = { 127 + .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | 128 + WDIOF_KEEPALIVEPING, 129 + .identity = "Orion5x Watchdog", 130 + }; 131 + 132 + 133 + static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, 134 + unsigned long arg) 135 + { 136 + int ret = -ENOTTY; 137 + int time; 138 + 139 + switch (cmd) { 140 + case WDIOC_GETSUPPORT: 141 + ret = copy_to_user((struct watchdog_info *)arg, &ident, 142 + sizeof(ident)) ? -EFAULT : 0; 143 + break; 144 + 145 + case WDIOC_GETSTATUS: 146 + case WDIOC_GETBOOTSTATUS: 147 + ret = put_user(0, (int *)arg); 148 + break; 149 + 150 + case WDIOC_KEEPALIVE: 151 + wdt_enable(); 152 + ret = 0; 153 + break; 154 + 155 + case WDIOC_SETTIMEOUT: 156 + ret = get_user(time, (int *)arg); 157 + if (ret) 158 + break; 159 + 160 + if (time <= 0 || time > WDT_MAX_DURATION) { 161 + ret = -EINVAL; 162 + break; 163 + } 164 + heartbeat = time; 165 + wdt_enable(); 166 + /* Fall through */ 167 + 168 + case WDIOC_GETTIMEOUT: 169 + ret = put_user(heartbeat, (int *)arg); 170 + break; 171 + 172 + case WDIOC_GETTIMELEFT: 173 + if (orion5x_wdt_get_timeleft(&time)) { 174 + ret = -EINVAL; 175 + break; 176 + } 177 + ret = put_user(time, (int *)arg); 178 + break; 179 + } 180 + return ret; 181 + } 182 + 183 + static int orion5x_wdt_release(struct inode *inode, struct file *file) 184 + { 185 + if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) 186 + wdt_disable(); 187 + else 188 + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " 189 + "timer will not stop\n"); 190 + clear_bit(WDT_IN_USE, &wdt_status); 191 + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); 192 + 193 + return 0; 194 + } 195 + 196 + 197 + static const struct file_operations orion5x_wdt_fops = { 198 + .owner = THIS_MODULE, 199 + .llseek = no_llseek, 200 + .write = orion5x_wdt_write, 201 + .unlocked_ioctl = orion5x_wdt_ioctl, 202 + .open = orion5x_wdt_open, 203 + .release = orion5x_wdt_release, 204 + }; 205 + 206 + static struct miscdevice orion5x_wdt_miscdev = { 207 + .minor = WATCHDOG_MINOR, 208 + .name = "watchdog", 209 + .fops = &orion5x_wdt_fops, 210 + }; 211 + 212 + static int __init orion5x_wdt_init(void) 213 + { 214 + int ret; 215 + 216 + spin_lock_init(&wdt_lock); 217 + 218 + ret = misc_register(&orion5x_wdt_miscdev); 219 + if (ret == 0) 220 + printk("Orion5x Watchdog Timer: heartbeat %d sec\n", 221 + heartbeat); 222 + 223 + return ret; 224 + } 225 + 226 + static void __exit orion5x_wdt_exit(void) 227 + { 228 + misc_deregister(&orion5x_wdt_miscdev); 229 + } 230 + 231 + module_init(orion5x_wdt_init); 232 + module_exit(orion5x_wdt_exit); 233 + 234 + MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>"); 235 + MODULE_DESCRIPTION("Orion5x Processor Watchdog"); 236 + 237 + module_param(heartbeat, int, 0); 238 + MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is " 239 + __MODULE_STRING(WDT_MAX_DURATION) ")"); 240 + 241 + module_param(nowayout, int, 0); 242 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); 243 + 244 + MODULE_LICENSE("GPL"); 245 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+392
drivers/watchdog/w83697ug_wdt.c
··· 1 + /* 2 + * w83697ug/uf WDT driver 3 + * 4 + * (c) Copyright 2008 Flemming Fransen <ff@nrvissing.net> 5 + * reused original code to supoprt w83697ug/uf. 6 + * 7 + * Based on w83627hf_wdt.c which is based on advantechwdt.c 8 + * which is based on wdt.c. 9 + * Original copyright messages: 10 + * 11 + * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> 12 + * added support for W83627THF. 13 + * 14 + * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com> 15 + * 16 + * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl> 17 + * 18 + * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. 19 + * http://www.redhat.com 20 + * 21 + * This program is free software; you can redistribute it and/or 22 + * modify it under the terms of the GNU General Public License 23 + * as published by the Free Software Foundation; either version 24 + * 2 of the License, or (at your option) any later version. 25 + * 26 + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 27 + * warranty for any of this software. This material is provided 28 + * "AS-IS" and at no charge. 29 + * 30 + * (c) Copyright 1995 Alan Cox <alan@redhat.com> 31 + */ 32 + 33 + #include <linux/module.h> 34 + #include <linux/moduleparam.h> 35 + #include <linux/types.h> 36 + #include <linux/miscdevice.h> 37 + #include <linux/watchdog.h> 38 + #include <linux/fs.h> 39 + #include <linux/ioport.h> 40 + #include <linux/notifier.h> 41 + #include <linux/reboot.h> 42 + #include <linux/init.h> 43 + #include <linux/spinlock.h> 44 + #include <linux/io.h> 45 + #include <linux/uaccess.h> 46 + 47 + #include <asm/system.h> 48 + 49 + #define WATCHDOG_NAME "w83697ug/uf WDT" 50 + #define PFX WATCHDOG_NAME ": " 51 + #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ 52 + 53 + static unsigned long wdt_is_open; 54 + static char expect_close; 55 + static DEFINE_SPINLOCK(io_lock); 56 + 57 + static int wdt_io = 0x2e; 58 + module_param(wdt_io, int, 0); 59 + MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)"); 60 + 61 + static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ 62 + module_param(timeout, int, 0); 63 + MODULE_PARM_DESC(timeout, 64 + "Watchdog timeout in seconds. 1<= timeout <=255 (default=" 65 + __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); 66 + 67 + static int nowayout = WATCHDOG_NOWAYOUT; 68 + module_param(nowayout, int, 0); 69 + MODULE_PARM_DESC(nowayout, 70 + "Watchdog cannot be stopped once started (default=" 71 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 72 + 73 + /* 74 + * Kernel methods. 75 + */ 76 + 77 + #define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */ 78 + #define WDT_EFIR (wdt_io+0) /* Extended Function Index Register 79 + (same as EFER) */ 80 + #define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */ 81 + 82 + static void w83697ug_select_wd_register(void) 83 + { 84 + unsigned char c; 85 + unsigned char version; 86 + 87 + outb_p(0x87, WDT_EFER); /* Enter extended function mode */ 88 + outb_p(0x87, WDT_EFER); /* Again according to manual */ 89 + 90 + outb(0x20, WDT_EFER); /* check chip version */ 91 + version = inb(WDT_EFDR); 92 + 93 + if (version == 0x68) { /* W83697UG */ 94 + printk(KERN_INFO PFX "Watchdog chip version 0x%02x = " 95 + "W83697UG/UF found at 0x%04x\n", version, wdt_io); 96 + 97 + outb_p(0x2b, WDT_EFER); 98 + c = inb_p(WDT_EFDR); /* select WDT0 */ 99 + c &= ~0x04; 100 + outb_p(0x2b, WDT_EFER); 101 + outb_p(c, WDT_EFDR); /* set pin118 to WDT0 */ 102 + 103 + } else { 104 + printk(KERN_ERR PFX "No W83697UG/UF could be found\n"); 105 + return -EIO; 106 + } 107 + 108 + outb_p(0x07, WDT_EFER); /* point to logical device number reg */ 109 + outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */ 110 + outb_p(0x30, WDT_EFER); /* select CR30 */ 111 + c = inb_p(WDT_EFDR); 112 + outb_p(c || 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */ 113 + } 114 + 115 + static void w83697ug_unselect_wd_register(void) 116 + { 117 + outb_p(0xAA, WDT_EFER); /* Leave extended function mode */ 118 + } 119 + 120 + static void w83697ug_init(void) 121 + { 122 + unsigned char t; 123 + 124 + w83697ug_select_wd_register(); 125 + 126 + outb_p(0xF6, WDT_EFER); /* Select CRF6 */ 127 + t = inb_p(WDT_EFDR); /* read CRF6 */ 128 + if (t != 0) { 129 + printk(KERN_INFO PFX "Watchdog already running." 130 + " Resetting timeout to %d sec\n", timeout); 131 + outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ 132 + } 133 + outb_p(0xF5, WDT_EFER); /* Select CRF5 */ 134 + t = inb_p(WDT_EFDR); /* read CRF5 */ 135 + t &= ~0x0C; /* set second mode & 136 + disable keyboard turning off watchdog */ 137 + outb_p(t, WDT_EFDR); /* Write back to CRF5 */ 138 + 139 + w83697ug_unselect_wd_register(); 140 + } 141 + 142 + static void wdt_ctrl(int timeout) 143 + { 144 + spin_lock(&io_lock); 145 + 146 + w83697ug_select_wd_register(); 147 + 148 + outb_p(0xF4, WDT_EFER); /* Select CRF4 */ 149 + outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */ 150 + 151 + w83697ug_unselect_wd_register(); 152 + 153 + spin_unlock(&io_lock); 154 + } 155 + 156 + static int wdt_ping(void) 157 + { 158 + wdt_ctrl(timeout); 159 + return 0; 160 + } 161 + 162 + static int wdt_disable(void) 163 + { 164 + wdt_ctrl(0); 165 + return 0; 166 + } 167 + 168 + static int wdt_set_heartbeat(int t) 169 + { 170 + if (t < 1 || t > 255) 171 + return -EINVAL; 172 + 173 + timeout = t; 174 + return 0; 175 + } 176 + 177 + static ssize_t wdt_write(struct file *file, const char __user *buf, 178 + size_t count, loff_t *ppos) 179 + { 180 + if (count) { 181 + if (!nowayout) { 182 + size_t i; 183 + 184 + expect_close = 0; 185 + 186 + for (i = 0; i != count; i++) { 187 + char c; 188 + if (get_user(c, buf + i)) 189 + return -EFAULT; 190 + if (c == 'V') 191 + expect_close = 42; 192 + } 193 + } 194 + wdt_ping(); 195 + } 196 + return count; 197 + } 198 + 199 + static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 200 + { 201 + void __user *argp = (void __user *)arg; 202 + int __user *p = argp; 203 + int new_timeout; 204 + static const struct watchdog_info ident = { 205 + .options = WDIOF_KEEPALIVEPING | 206 + WDIOF_SETTIMEOUT | 207 + WDIOF_MAGICCLOSE, 208 + .firmware_version = 1, 209 + .identity = "W83697UG WDT", 210 + }; 211 + 212 + switch (cmd) { 213 + case WDIOC_GETSUPPORT: 214 + if (copy_to_user(argp, &ident, sizeof(ident))) 215 + return -EFAULT; 216 + break; 217 + 218 + case WDIOC_GETSTATUS: 219 + case WDIOC_GETBOOTSTATUS: 220 + return put_user(0, p); 221 + 222 + case WDIOC_SETOPTIONS: 223 + { 224 + int options, retval = -EINVAL; 225 + 226 + if (get_user(options, p)) 227 + return -EFAULT; 228 + 229 + if (options & WDIOS_DISABLECARD) { 230 + wdt_disable(); 231 + retval = 0; 232 + } 233 + 234 + if (options & WDIOS_ENABLECARD) { 235 + wdt_ping(); 236 + retval = 0; 237 + } 238 + 239 + return retval; 240 + } 241 + 242 + case WDIOC_KEEPALIVE: 243 + wdt_ping(); 244 + break; 245 + 246 + case WDIOC_SETTIMEOUT: 247 + if (get_user(new_timeout, p)) 248 + return -EFAULT; 249 + if (wdt_set_heartbeat(new_timeout)) 250 + return -EINVAL; 251 + wdt_ping(); 252 + /* Fall */ 253 + 254 + case WDIOC_GETTIMEOUT: 255 + return put_user(timeout, p); 256 + 257 + default: 258 + return -ENOTTY; 259 + } 260 + return 0; 261 + } 262 + 263 + static int wdt_open(struct inode *inode, struct file *file) 264 + { 265 + if (test_and_set_bit(0, &wdt_is_open)) 266 + return -EBUSY; 267 + /* 268 + * Activate 269 + */ 270 + 271 + wdt_ping(); 272 + return nonseekable_open(inode, file); 273 + } 274 + 275 + static int wdt_close(struct inode *inode, struct file *file) 276 + { 277 + if (expect_close == 42) 278 + wdt_disable(); 279 + else { 280 + printk(KERN_CRIT PFX 281 + "Unexpected close, not stopping watchdog!\n"); 282 + wdt_ping(); 283 + } 284 + expect_close = 0; 285 + clear_bit(0, &wdt_is_open); 286 + return 0; 287 + } 288 + 289 + /* 290 + * Notifier for system down 291 + */ 292 + 293 + static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 294 + void *unused) 295 + { 296 + if (code == SYS_DOWN || code == SYS_HALT) 297 + wdt_disable(); /* Turn the WDT off */ 298 + 299 + return NOTIFY_DONE; 300 + } 301 + 302 + /* 303 + * Kernel Interfaces 304 + */ 305 + 306 + static const struct file_operations wdt_fops = { 307 + .owner = THIS_MODULE, 308 + .llseek = no_llseek, 309 + .write = wdt_write, 310 + .unlocked_ioctl = wdt_ioctl, 311 + .open = wdt_open, 312 + .release = wdt_close, 313 + }; 314 + 315 + static struct miscdevice wdt_miscdev = { 316 + .minor = WATCHDOG_MINOR, 317 + .name = "watchdog", 318 + .fops = &wdt_fops, 319 + }; 320 + 321 + /* 322 + * The WDT needs to learn about soft shutdowns in order to 323 + * turn the timebomb registers off. 324 + */ 325 + 326 + static struct notifier_block wdt_notifier = { 327 + .notifier_call = wdt_notify_sys, 328 + }; 329 + 330 + static int __init wdt_init(void) 331 + { 332 + int ret; 333 + 334 + printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n"); 335 + 336 + if (wdt_set_heartbeat(timeout)) { 337 + wdt_set_heartbeat(WATCHDOG_TIMEOUT); 338 + printk(KERN_INFO PFX 339 + "timeout value must be 1<=timeout<=255, using %d\n", 340 + WATCHDOG_TIMEOUT); 341 + } 342 + 343 + if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { 344 + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", 345 + wdt_io); 346 + ret = -EIO; 347 + goto out; 348 + } 349 + 350 + w83697ug_init(); 351 + 352 + ret = register_reboot_notifier(&wdt_notifier); 353 + if (ret != 0) { 354 + printk(KERN_ERR PFX 355 + "cannot register reboot notifier (err=%d)\n", ret); 356 + goto unreg_regions; 357 + } 358 + 359 + ret = misc_register(&wdt_miscdev); 360 + if (ret != 0) { 361 + printk(KERN_ERR PFX 362 + "cannot register miscdev on minor=%d (err=%d)\n", 363 + WATCHDOG_MINOR, ret); 364 + goto unreg_reboot; 365 + } 366 + 367 + printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", 368 + timeout, nowayout); 369 + 370 + out: 371 + return ret; 372 + unreg_reboot: 373 + unregister_reboot_notifier(&wdt_notifier); 374 + unreg_regions: 375 + release_region(wdt_io, 1); 376 + goto out; 377 + } 378 + 379 + static void __exit wdt_exit(void) 380 + { 381 + misc_deregister(&wdt_miscdev); 382 + unregister_reboot_notifier(&wdt_notifier); 383 + release_region(wdt_io, 1); 384 + } 385 + 386 + module_init(wdt_init); 387 + module_exit(wdt_exit); 388 + 389 + MODULE_LICENSE("GPL"); 390 + MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>"); 391 + MODULE_DESCRIPTION("w83697ug/uf WDT driver"); 392 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);