21 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
31 #include <linux/watchdog.h>
41 #define DRV_NAME "sch311x_wdt"
45 #define WDT_TIME_OUT 0x65
51 static unsigned long sch311x_wdt_is_open;
52 static char sch311x_wdt_expect_close;
55 static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e, 0x00 };
67 static unsigned short force_id;
71 #define WATCHDOG_TIMEOUT 60
75 "Watchdog timeout in seconds. 1<= timeout <=15300, default="
81 "Watchdog cannot be stopped once started (default="
88 static inline void sch311x_sio_enter(
int sio_config_port)
90 outb(0x55, sio_config_port);
93 static inline void sch311x_sio_exit(
int sio_config_port)
95 outb(0xaa, sio_config_port);
98 static inline int sch311x_sio_inb(
int sio_config_port,
int reg)
100 outb(reg, sio_config_port);
101 return inb(sio_config_port + 1);
104 static inline void sch311x_sio_outb(
int sio_config_port,
int reg,
int val)
106 outb(reg, sio_config_port);
107 outb(val, sio_config_port + 1);
114 static void sch311x_wdt_set_timeout(
int t)
116 unsigned char timeout_unit = 0x80;
137 static void sch311x_wdt_start(
void)
141 spin_lock(&sch311x_wdt_data.io_lock);
144 sch311x_wdt_set_timeout(timeout);
154 t =
inb(sch311x_wdt_data.runtime_reg +
GP60);
155 outb((t & ~0x0d) | 0x0c, sch311x_wdt_data.runtime_reg +
GP60);
157 spin_unlock(&sch311x_wdt_data.io_lock);
161 static void sch311x_wdt_stop(
void)
165 spin_lock(&sch311x_wdt_data.io_lock);
168 t =
inb(sch311x_wdt_data.runtime_reg +
GP60);
169 outb((t & ~0x0d) | 0x01, sch311x_wdt_data.runtime_reg +
GP60);
171 sch311x_wdt_set_timeout(0);
173 spin_unlock(&sch311x_wdt_data.io_lock);
176 static void sch311x_wdt_keepalive(
void)
178 spin_lock(&sch311x_wdt_data.io_lock);
179 sch311x_wdt_set_timeout(timeout);
180 spin_unlock(&sch311x_wdt_data.io_lock);
183 static int sch311x_wdt_set_heartbeat(
int t)
185 if (t < 1 || t > (255*60))
191 t = (((t - 1) / 60) + 1) * 60;
197 static void sch311x_wdt_get_status(
int *
status)
199 unsigned char new_status;
203 spin_lock(&sch311x_wdt_data.io_lock);
215 new_status =
inb(sch311x_wdt_data.runtime_reg +
WDT_CTRL);
216 if (new_status & 0x01)
219 spin_unlock(&sch311x_wdt_data.io_lock);
227 size_t count, loff_t *ppos)
233 sch311x_wdt_expect_close = 0;
235 for (i = 0; i !=
count; i++) {
240 sch311x_wdt_expect_close = 42;
243 sch311x_wdt_keepalive();
248 static long sch311x_wdt_ioctl(
struct file *file,
unsigned int cmd,
259 .firmware_version = 1,
271 sch311x_wdt_get_status(&status);
275 return put_user(sch311x_wdt_data.boot_status, p);
294 sch311x_wdt_keepalive();
300 if (sch311x_wdt_set_heartbeat(new_timeout))
302 sch311x_wdt_keepalive();
312 static int sch311x_wdt_open(
struct inode *
inode,
struct file *file)
323 static int sch311x_wdt_close(
struct inode *inode,
struct file *file)
325 if (sch311x_wdt_expect_close == 42) {
328 pr_crit(
"Unexpected close, not stopping watchdog!\n");
329 sch311x_wdt_keepalive();
332 sch311x_wdt_expect_close = 0;
343 .write = sch311x_wdt_write,
344 .unlocked_ioctl = sch311x_wdt_ioctl,
345 .open = sch311x_wdt_open,
346 .release = sch311x_wdt_close,
349 static struct miscdevice sch311x_wdt_miscdev = {
352 .fops = &sch311x_wdt_fops,
367 dev_err(dev,
"Failed to request region 0x%04x-0x%04x.\n",
368 sch311x_wdt_data.runtime_reg +
GP60,
369 sch311x_wdt_data.runtime_reg +
GP60);
376 dev_err(dev,
"Failed to request region 0x%04x-0x%04x.\n",
378 sch311x_wdt_data.runtime_reg +
WDT_CTRL);
380 goto exit_release_region;
399 if (sch311x_wdt_set_heartbeat(timeout)) {
401 dev_info(dev,
"timeout value must be 1<=x<=15300, using %d\n",
406 sch311x_wdt_get_status(&sch311x_wdt_data.boot_status);
412 dev_err(dev,
"cannot register miscdev on minor=%d (err=%d)\n",
414 goto exit_release_region2;
418 "SMSC SCH311x WDT initialized. timeout=%d sec (nowayout=%d)\n",
423 exit_release_region2:
427 sch311x_wdt_data.runtime_reg = 0;
442 sch311x_wdt_data.runtime_reg = 0;
453 .probe = sch311x_wdt_probe,
455 .shutdown = sch311x_wdt_shutdown,
462 static int __init sch311x_detect(
int sio_config_port,
unsigned short *
addr)
465 unsigned short base_addr;
468 sch311x_sio_enter(sio_config_port);
472 reg = force_id ? force_id : sch311x_sio_inb(sio_config_port, 0x20);
473 if (!(
reg == 0x7c ||
reg == 0x7d ||
reg == 0x7f)) {
477 dev_id =
reg == 0x7c ? 2 :
reg == 0x7d ? 4 : 6;
480 sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
483 if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
484 pr_info(
"Seems that LDN 0x0a is not active...\n");
487 base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
488 sch311x_sio_inb(sio_config_port, 0x61);
490 pr_err(
"Base address not set\n");
496 pr_info(
"Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
499 sch311x_sio_exit(sio_config_port);
503 static int __init sch311x_wdt_init(
void)
505 int err,
i, found = 0;
506 unsigned short addr = 0;
508 for (i = 0; !found && sch311x_ioports[
i]; i++)
509 if (sch311x_detect(sch311x_ioports[i], &addr) == 0)
515 sch311x_wdt_data.runtime_reg =
addr;
521 sch311x_wdt_pdev = platform_device_register_simple(
DRV_NAME, addr,
524 if (IS_ERR(sch311x_wdt_pdev)) {
525 err = PTR_ERR(sch311x_wdt_pdev);
526 goto unreg_platform_driver;
531 unreg_platform_driver:
536 static void __exit sch311x_wdt_exit(
void)