aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/w83627hf_wdt.c132
1 files changed, 76 insertions, 56 deletions
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index c5d34f46e7ad..e24b21082874 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -70,80 +70,102 @@ MODULE_PARM_DESC(nowayout,
70 (same as EFER) */ 70 (same as EFER) */
71#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */ 71#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
72 72
73static void w83627hf_select_wd_register(void) 73#define W83627HF_LD_WDT 0x08
74
75static void superio_outb(int reg, int val)
76{
77 outb(reg, WDT_EFER);
78 outb(val, WDT_EFDR);
79}
80
81static inline int superio_inb(int reg)
82{
83 outb(reg, WDT_EFER);
84 return inb(WDT_EFDR);
85}
86
87static int superio_enter(void)
74{ 88{
89 if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME))
90 return -EBUSY;
91
75 outb_p(0x87, WDT_EFER); /* Enter extended function mode */ 92 outb_p(0x87, WDT_EFER); /* Enter extended function mode */
76 outb_p(0x87, WDT_EFER); /* Again according to manual */ 93 outb_p(0x87, WDT_EFER); /* Again according to manual */
77 outb_p(0x07, WDT_EFER); /* point to logical device number reg */ 94
78 outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */ 95 return 0;
79} 96}
80 97
81static void w83627hf_unselect_wd_register(void) 98static void superio_select(int ld)
99{
100 superio_outb(0x07, ld);
101}
102
103static void superio_exit(void)
82{ 104{
83 outb_p(0xAA, WDT_EFER); /* Leave extended function mode */ 105 outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
106 release_region(wdt_io, 2);
84} 107}
85 108
86/* tyan motherboards seem to set F5 to 0x4C ? 109/* tyan motherboards seem to set F5 to 0x4C ?
87 * So explicitly init to appropriate value. */ 110 * So explicitly init to appropriate value. */
88 111
89static void w83627hf_init(struct watchdog_device *wdog) 112static int w83627hf_init(struct watchdog_device *wdog)
90{ 113{
114 int ret;
91 unsigned char t; 115 unsigned char t;
92 116
93 w83627hf_select_wd_register(); 117 ret = superio_enter();
118 if (ret)
119 return ret;
94 120
95 outb(0x20, WDT_EFER); /* check chip version */ 121 superio_select(W83627HF_LD_WDT);
96 t = inb(WDT_EFDR); 122 t = superio_inb(0x20); /* check chip version */
97 if (t == 0x82) { /* W83627THF */ 123 if (t == 0x82) { /* W83627THF */
98 outb_p(0x2b, WDT_EFER); /* select GPIO3 */ 124 t = (superio_inb(0x2b) & 0xf7);
99 t = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ 125 superio_outb(0x2b, t | 0x04); /* set GPIO3 to WDT0 */
100 outb_p(0x2b, WDT_EFER);
101 outb_p(t, WDT_EFDR); /* set GPIO3 to WDT0 */
102 } else if (t == 0x88 || t == 0xa0) { /* W83627EHF / W83627DHG */ 126 } else if (t == 0x88 || t == 0xa0) { /* W83627EHF / W83627DHG */
103 outb_p(0x2d, WDT_EFER); /* select GPIO5 */ 127 t = superio_inb(0x2d);
104 t = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */ 128 superio_outb(0x2d, t & ~0x01); /* set GPIO5 to WDT0 */
105 outb_p(0x2d, WDT_EFER);
106 outb_p(t, WDT_EFDR); /* set GPIO5 to WDT0 */
107 } 129 }
108 130
109 outb_p(0x30, WDT_EFER); /* select CR30 */ 131 /* set CR30 bit 0 to activate GPIO2 */
110 t = inb(WDT_EFDR); 132 t = superio_inb(0x30);
111 if (!(t & 0x01)) 133 if (!(t & 0x01))
112 outb_p(t | 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */ 134 superio_outb(0x30, t | 0x01);
113 135
114 outb_p(0xF6, WDT_EFER); /* Select CRF6 */ 136 t = superio_inb(0xF6);
115 t = inb_p(WDT_EFDR); /* read CRF6 */
116 if (t != 0) { 137 if (t != 0) {
117 pr_info("Watchdog already running. Resetting timeout to %d sec\n", 138 pr_info("Watchdog already running. Resetting timeout to %d sec\n",
118 wdog->timeout); 139 wdog->timeout);
119 outb_p(wdog->timeout, WDT_EFDR); /* Write back to CRF6 */ 140 superio_outb(0xF6, wdog->timeout);
120 } 141 }
121 142
122 outb_p(0xF5, WDT_EFER); /* Select CRF5 */ 143 /* set second mode & disable keyboard turning off watchdog */
123 t = inb_p(WDT_EFDR); /* read CRF5 */ 144 t = superio_inb(0xF5) & ~0x0C;
124 t &= ~0x0C; /* set second mode & disable keyboard 145 /* enable the WDTO# output low pulse to the KBRST# pin */
125 turning off watchdog */ 146 t |= 0x02;
126 t |= 0x02; /* enable the WDTO# output low pulse 147 superio_outb(0xF5, t);
127 to the KBRST# pin (PIN60) */ 148
128 outb_p(t, WDT_EFDR); /* Write back to CRF5 */ 149 /* disable keyboard & mouse turning off watchdog */
129 150 t = superio_inb(0xF7) & ~0xC0;
130 outb_p(0xF7, WDT_EFER); /* Select CRF7 */ 151 superio_outb(0xF7, t);
131 t = inb_p(WDT_EFDR); /* read CRF7 */ 152
132 t &= ~0xC0; /* disable keyboard & mouse turning off 153 superio_exit();
133 watchdog */ 154
134 outb_p(t, WDT_EFDR); /* Write back to CRF7 */ 155 return 0;
135
136 w83627hf_unselect_wd_register();
137} 156}
138 157
139static int wdt_set_time(unsigned int timeout) 158static int wdt_set_time(unsigned int timeout)
140{ 159{
141 w83627hf_select_wd_register(); 160 int ret;
142 161
143 outb_p(0xF6, WDT_EFER); /* Select CRF6 */ 162 ret = superio_enter();
144 outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ 163 if (ret)
164 return ret;
145 165
146 w83627hf_unselect_wd_register(); 166 superio_select(W83627HF_LD_WDT);
167 superio_outb(0xF6, timeout);
168 superio_exit();
147 169
148 return 0; 170 return 0;
149} 171}
@@ -168,13 +190,15 @@ static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
168static unsigned int wdt_get_time(struct watchdog_device *wdog) 190static unsigned int wdt_get_time(struct watchdog_device *wdog)
169{ 191{
170 unsigned int timeleft; 192 unsigned int timeleft;
193 int ret;
171 194
172 w83627hf_select_wd_register(); 195 ret = superio_enter();
173 196 if (ret)
174 outb_p(0xF6, WDT_EFER); /* Select CRF6 */ 197 return 0;
175 timeleft = inb_p(WDT_EFDR); /* Read Timeout counter to CRF6 */
176 198
177 w83627hf_unselect_wd_register(); 199 superio_select(W83627HF_LD_WDT);
200 timeleft = superio_inb(0xF6);
201 superio_exit();
178 202
179 return timeleft; 203 return timeleft;
180} 204}
@@ -231,20 +255,19 @@ static int __init wdt_init(void)
231 255
232 pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); 256 pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n");
233 257
234 if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
235 pr_err("I/O address 0x%04x already in use\n", wdt_io);
236 return -EIO;
237 }
238
239 watchdog_init_timeout(&wdt_dev, timeout, NULL); 258 watchdog_init_timeout(&wdt_dev, timeout, NULL);
240 watchdog_set_nowayout(&wdt_dev, nowayout); 259 watchdog_set_nowayout(&wdt_dev, nowayout);
241 260
242 w83627hf_init(&wdt_dev); 261 ret = w83627hf_init(&wdt_dev);
262 if (ret) {
263 pr_err("failed to initialize watchdog (err=%d)\n", ret);
264 return ret;
265 }
243 266
244 ret = register_reboot_notifier(&wdt_notifier); 267 ret = register_reboot_notifier(&wdt_notifier);
245 if (ret != 0) { 268 if (ret != 0) {
246 pr_err("cannot register reboot notifier (err=%d)\n", ret); 269 pr_err("cannot register reboot notifier (err=%d)\n", ret);
247 goto unreg_regions; 270 return ret;
248 } 271 }
249 272
250 ret = watchdog_register_device(&wdt_dev); 273 ret = watchdog_register_device(&wdt_dev);
@@ -258,8 +281,6 @@ static int __init wdt_init(void)
258 281
259unreg_reboot: 282unreg_reboot:
260 unregister_reboot_notifier(&wdt_notifier); 283 unregister_reboot_notifier(&wdt_notifier);
261unreg_regions:
262 release_region(wdt_io, 1);
263 return ret; 284 return ret;
264} 285}
265 286
@@ -267,7 +288,6 @@ static void __exit wdt_exit(void)
267{ 288{
268 watchdog_unregister_device(&wdt_dev); 289 watchdog_unregister_device(&wdt_dev);
269 unregister_reboot_notifier(&wdt_notifier); 290 unregister_reboot_notifier(&wdt_notifier);
270 release_region(wdt_io, 1);
271} 291}
272 292
273module_init(wdt_init); 293module_init(wdt_init);