aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog')
-rw-r--r--drivers/char/watchdog/at32ap700x_wdt.c64
1 files changed, 53 insertions, 11 deletions
diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c
index 6e7c9588b1b9..fcd55c600b87 100644
--- a/drivers/char/watchdog/at32ap700x_wdt.c
+++ b/drivers/char/watchdog/at32ap700x_wdt.c
@@ -30,6 +30,11 @@ MODULE_PARM_DESC(timeout,
30 "Timeout value. Limited to be 1 or 2 seconds. (default=" 30 "Timeout value. Limited to be 1 or 2 seconds. (default="
31 __MODULE_STRING(TIMEOUT_DEFAULT) ")"); 31 __MODULE_STRING(TIMEOUT_DEFAULT) ")");
32 32
33static int nowayout = WATCHDOG_NOWAYOUT;
34module_param(nowayout, int, 0);
35MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
36 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
37
33/* Watchdog registers and write/read macro */ 38/* Watchdog registers and write/read macro */
34#define WDT_CTRL 0x00 39#define WDT_CTRL 0x00
35#define WDT_CTRL_EN 0 40#define WDT_CTRL_EN 0
@@ -54,6 +59,7 @@ struct wdt_at32ap700x {
54}; 59};
55 60
56static struct wdt_at32ap700x *wdt; 61static struct wdt_at32ap700x *wdt;
62static char expect_release;
57 63
58/* 64/*
59 * Disable the watchdog. 65 * Disable the watchdog.
@@ -102,15 +108,19 @@ static int at32_wdt_open(struct inode *inode, struct file *file)
102} 108}
103 109
104/* 110/*
105 * Close the watchdog device. If CONFIG_WATCHDOG_NOWAYOUT is _not_ defined then 111 * Close the watchdog device.
106 * the watchdog is also disabled.
107 */ 112 */
108static int at32_wdt_close(struct inode *inode, struct file *file) 113static int at32_wdt_close(struct inode *inode, struct file *file)
109{ 114{
110#ifndef CONFIG_WATCHDOG_NOWAYOUT 115 if (expect_release == 42) {
111 at32_wdt_stop(); 116 at32_wdt_stop();
112#endif 117 } else {
118 dev_dbg(wdt->miscdev.parent,
119 "Unexpected close, not stopping watchdog!\n");
120 at32_wdt_pat();
121 }
113 clear_bit(1, &wdt->users); 122 clear_bit(1, &wdt->users);
123 expect_release = 0;
114 return 0; 124 return 0;
115} 125}
116 126
@@ -136,7 +146,9 @@ static int at32_wdt_settimeout(int time)
136 146
137static struct watchdog_info at32_wdt_info = { 147static struct watchdog_info at32_wdt_info = {
138 .identity = "at32ap700x watchdog", 148 .identity = "at32ap700x watchdog",
139 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 149 .options = WDIOF_SETTIMEOUT |
150 WDIOF_KEEPALIVEPING |
151 WDIOF_MAGICCLOSE,
140}; 152};
141 153
142/* 154/*
@@ -191,10 +203,35 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file,
191 return ret; 203 return ret;
192} 204}
193 205
194static ssize_t at32_wdt_write(struct file *file, const char *data, size_t len, 206static ssize_t at32_wdt_write(struct file *file, const char __user *data,
195 loff_t *ppos) 207 size_t len, loff_t *ppos)
196{ 208{
197 at32_wdt_pat(); 209 /* See if we got the magic character 'V' and reload the timer */
210 if (len) {
211 if (!nowayout) {
212 size_t i;
213
214 /*
215 * note: just in case someone wrote the magic
216 * character five months ago...
217 */
218 expect_release = 0;
219
220 /*
221 * scan to see whether or not we got the magic
222 * character
223 */
224 for (i = 0; i != len; i++) {
225 char c;
226 if (get_user(c, data+i))
227 return -EFAULT;
228 if (c == 'V')
229 expect_release = 42;
230 }
231 }
232 /* someone wrote to us, we should pat the watchdog */
233 at32_wdt_pat();
234 }
198 return len; 235 return len;
199} 236}
200 237
@@ -255,8 +292,9 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
255 292
256 platform_set_drvdata(pdev, wdt); 293 platform_set_drvdata(pdev, wdt);
257 wdt->miscdev.parent = &pdev->dev; 294 wdt->miscdev.parent = &pdev->dev;
258 dev_info(&pdev->dev, "AT32AP700X WDT at 0x%p, timeout %d sec\n", 295 dev_info(&pdev->dev,
259 wdt->regs, wdt->timeout); 296 "AT32AP700X WDT at 0x%p, timeout %d sec (nowayout=%d)\n",
297 wdt->regs, wdt->timeout, nowayout);
260 298
261 return 0; 299 return 0;
262 300
@@ -271,6 +309,10 @@ err_free:
271static int __exit at32_wdt_remove(struct platform_device *pdev) 309static int __exit at32_wdt_remove(struct platform_device *pdev)
272{ 310{
273 if (wdt && platform_get_drvdata(pdev) == wdt) { 311 if (wdt && platform_get_drvdata(pdev) == wdt) {
312 /* Stop the timer before we leave */
313 if (!nowayout)
314 at32_wdt_stop();
315
274 misc_deregister(&wdt->miscdev); 316 misc_deregister(&wdt->miscdev);
275 iounmap(wdt->regs); 317 iounmap(wdt->regs);
276 kfree(wdt); 318 kfree(wdt);