diff options
author | Andrew Paprocki <andrew@ishiboo.com> | 2008-02-10 22:11:15 -0500 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2008-03-06 06:10:07 -0500 |
commit | 5e69960865ab6033a129f9ee35264adb2a1cfc94 (patch) | |
tree | 0fac0e3ffbbe1e9b2e097bf13e9d4ddd10c357c2 /drivers/watchdog | |
parent | d7fe321eeba58f0a37cc4324d10e52092be457e0 (diff) |
[WATCHDOG] it8712f_wdt support for 16-bit timeout values, WDIOC_GETSTATUS
This patch adds support for 16-bit watchdog timeout values which are
available in chip revisions >= 0x08. Values <= 65535 are seconds precision,
otherwise minutes precision is used up to a maximum value of 3932100. Added
implementation for WDIOC_GETSTATUS which checks the WDT status bit in the
WDT control register.
Signed-off-by: Andrew Paprocki <andrew@ishiboo.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/it8712f_wdt.c | 78 |
1 files changed, 64 insertions, 14 deletions
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c index 1b6d7d1b715d..1efcad3b6fca 100644 --- a/drivers/watchdog/it8712f_wdt.c +++ b/drivers/watchdog/it8712f_wdt.c | |||
@@ -7,7 +7,8 @@ | |||
7 | * | 7 | * |
8 | * drivers/char/watchdog/scx200_wdt.c | 8 | * drivers/char/watchdog/scx200_wdt.c |
9 | * drivers/hwmon/it87.c | 9 | * drivers/hwmon/it87.c |
10 | * IT8712F EC-LPC I/O Preliminary Specification 0.9.2.pdf | 10 | * IT8712F EC-LPC I/O Preliminary Specification 0.8.2 |
11 | * IT8712F EC-LPC I/O Preliminary Specification 0.9.3 | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License as | 14 | * modify it under the terms of the GNU General Public License as |
@@ -40,6 +41,7 @@ MODULE_DESCRIPTION("IT8712F Watchdog Driver"); | |||
40 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
41 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 42 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
42 | 43 | ||
44 | static int max_units = 255; | ||
43 | static int margin = 60; /* in seconds */ | 45 | static int margin = 60; /* in seconds */ |
44 | module_param(margin, int, 0); | 46 | module_param(margin, int, 0); |
45 | MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); | 47 | MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); |
@@ -51,6 +53,7 @@ MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); | |||
51 | static struct semaphore it8712f_wdt_sem; | 53 | static struct semaphore it8712f_wdt_sem; |
52 | static unsigned expect_close; | 54 | static unsigned expect_close; |
53 | static spinlock_t io_lock; | 55 | static spinlock_t io_lock; |
56 | static unsigned char revision; | ||
54 | 57 | ||
55 | /* Dog Food address - We use the game port address */ | 58 | /* Dog Food address - We use the game port address */ |
56 | static unsigned short address; | 59 | static unsigned short address; |
@@ -108,6 +111,15 @@ superio_inw(int reg) | |||
108 | return val; | 111 | return val; |
109 | } | 112 | } |
110 | 113 | ||
114 | static void | ||
115 | superio_outw(int val, int reg) | ||
116 | { | ||
117 | outb(reg++, REG); | ||
118 | outb((val >> 8) & 0xff, VAL); | ||
119 | outb(reg, REG); | ||
120 | outb(val & 0xff, VAL); | ||
121 | } | ||
122 | |||
111 | static inline void | 123 | static inline void |
112 | superio_select(int ldn) | 124 | superio_select(int ldn) |
113 | { | 125 | { |
@@ -143,15 +155,33 @@ static void | |||
143 | it8712f_wdt_update_margin(void) | 155 | it8712f_wdt_update_margin(void) |
144 | { | 156 | { |
145 | int config = WDT_OUT_KRST | WDT_OUT_PWROK; | 157 | int config = WDT_OUT_KRST | WDT_OUT_PWROK; |
146 | 158 | int units = margin; | |
147 | printk(KERN_INFO NAME ": timer margin %d seconds\n", margin); | 159 | |
148 | 160 | /* Switch to minutes precision if the configured margin | |
149 | /* The timeout register only has 8bits wide */ | 161 | * value does not fit within the register width. |
150 | if (margin < 256) | 162 | */ |
151 | config |= WDT_UNIT_SEC; /* else UNIT are MINUTES */ | 163 | if (units <= max_units) { |
164 | config |= WDT_UNIT_SEC; /* else UNIT is MINUTES */ | ||
165 | printk(KERN_INFO NAME ": timer margin %d seconds\n", units); | ||
166 | } else { | ||
167 | units /= 60; | ||
168 | printk(KERN_INFO NAME ": timer margin %d minutes\n", units); | ||
169 | } | ||
152 | superio_outb(config, WDT_CONFIG); | 170 | superio_outb(config, WDT_CONFIG); |
153 | 171 | ||
154 | superio_outb((margin > 255) ? (margin / 60) : margin, WDT_TIMEOUT); | 172 | if (revision >= 0x08) |
173 | superio_outw(units, WDT_TIMEOUT); | ||
174 | else | ||
175 | superio_outb(units, WDT_TIMEOUT); | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | it8712f_wdt_get_status(void) | ||
180 | { | ||
181 | if (superio_inb(WDT_CONTROL) & 0x01) | ||
182 | return WDIOF_CARDRESET; | ||
183 | else | ||
184 | return 0; | ||
155 | } | 185 | } |
156 | 186 | ||
157 | static void | 187 | static void |
@@ -234,7 +264,7 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, | |||
234 | .firmware_version = 1, | 264 | .firmware_version = 1, |
235 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 265 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
236 | }; | 266 | }; |
237 | int new_margin; | 267 | int value; |
238 | 268 | ||
239 | switch (cmd) { | 269 | switch (cmd) { |
240 | default: | 270 | default: |
@@ -244,17 +274,27 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, | |||
244 | return -EFAULT; | 274 | return -EFAULT; |
245 | return 0; | 275 | return 0; |
246 | case WDIOC_GETSTATUS: | 276 | case WDIOC_GETSTATUS: |
277 | superio_enter(); | ||
278 | superio_select(LDN_GPIO); | ||
279 | |||
280 | value = it8712f_wdt_get_status(); | ||
281 | |||
282 | superio_exit(); | ||
283 | |||
284 | return put_user(value, p); | ||
247 | case WDIOC_GETBOOTSTATUS: | 285 | case WDIOC_GETBOOTSTATUS: |
248 | return put_user(0, p); | 286 | return put_user(0, p); |
249 | case WDIOC_KEEPALIVE: | 287 | case WDIOC_KEEPALIVE: |
250 | it8712f_wdt_ping(); | 288 | it8712f_wdt_ping(); |
251 | return 0; | 289 | return 0; |
252 | case WDIOC_SETTIMEOUT: | 290 | case WDIOC_SETTIMEOUT: |
253 | if (get_user(new_margin, p)) | 291 | if (get_user(value, p)) |
254 | return -EFAULT; | 292 | return -EFAULT; |
255 | if (new_margin < 1) | 293 | if (value < 1) |
294 | return -EINVAL; | ||
295 | if (value > (max_units * 60)) | ||
256 | return -EINVAL; | 296 | return -EINVAL; |
257 | margin = new_margin; | 297 | margin = value; |
258 | superio_enter(); | 298 | superio_enter(); |
259 | superio_select(LDN_GPIO); | 299 | superio_select(LDN_GPIO); |
260 | 300 | ||
@@ -262,6 +302,7 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, | |||
262 | 302 | ||
263 | superio_exit(); | 303 | superio_exit(); |
264 | it8712f_wdt_ping(); | 304 | it8712f_wdt_ping(); |
305 | /* Fall through */ | ||
265 | case WDIOC_GETTIMEOUT: | 306 | case WDIOC_GETTIMEOUT: |
266 | if (put_user(margin, p)) | 307 | if (put_user(margin, p)) |
267 | return -EFAULT; | 308 | return -EFAULT; |
@@ -336,9 +377,18 @@ it8712f_wdt_find(unsigned short *address) | |||
336 | } | 377 | } |
337 | 378 | ||
338 | err = 0; | 379 | err = 0; |
339 | printk(KERN_DEBUG NAME ": Found IT%04xF chip revision %d - " | 380 | revision = superio_inb(DEVREV) & 0x0f; |
381 | |||
382 | /* Later revisions have 16-bit values per datasheet 0.9.1 */ | ||
383 | if (revision >= 0x08) | ||
384 | max_units = 65535; | ||
385 | |||
386 | if (margin > (max_units * 60)) | ||
387 | margin = (max_units * 60); | ||
388 | |||
389 | printk(KERN_INFO NAME ": Found IT%04xF chip revision %d - " | ||
340 | "using DogFood address 0x%x\n", | 390 | "using DogFood address 0x%x\n", |
341 | chip_type, superio_inb(DEVREV) & 0x0f, *address); | 391 | chip_type, revision, *address); |
342 | 392 | ||
343 | exit: | 393 | exit: |
344 | superio_exit(); | 394 | superio_exit(); |