diff options
-rw-r--r-- | drivers/watchdog/orion5x_wdt.c | 57 |
1 files changed, 42 insertions, 15 deletions
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c index e81441f103dd..7529616739d2 100644 --- a/drivers/watchdog/orion5x_wdt.c +++ b/drivers/watchdog/orion5x_wdt.c | |||
@@ -42,7 +42,17 @@ static unsigned int wdt_tclk; | |||
42 | static unsigned long wdt_status; | 42 | static unsigned long wdt_status; |
43 | static spinlock_t wdt_lock; | 43 | static spinlock_t wdt_lock; |
44 | 44 | ||
45 | static void wdt_enable(void) | 45 | static void orion5x_wdt_ping(void) |
46 | { | ||
47 | spin_lock(&wdt_lock); | ||
48 | |||
49 | /* Reload watchdog duration */ | ||
50 | writel(wdt_tclk * heartbeat, WDT_VAL); | ||
51 | |||
52 | spin_unlock(&wdt_lock); | ||
53 | } | ||
54 | |||
55 | static void orion5x_wdt_enable(void) | ||
46 | { | 56 | { |
47 | u32 reg; | 57 | u32 reg; |
48 | 58 | ||
@@ -69,7 +79,7 @@ static void wdt_enable(void) | |||
69 | spin_unlock(&wdt_lock); | 79 | spin_unlock(&wdt_lock); |
70 | } | 80 | } |
71 | 81 | ||
72 | static void wdt_disable(void) | 82 | static void orion5x_wdt_disable(void) |
73 | { | 83 | { |
74 | u32 reg; | 84 | u32 reg; |
75 | 85 | ||
@@ -101,7 +111,7 @@ static int orion5x_wdt_open(struct inode *inode, struct file *file) | |||
101 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | 111 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) |
102 | return -EBUSY; | 112 | return -EBUSY; |
103 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 113 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
104 | wdt_enable(); | 114 | orion5x_wdt_enable(); |
105 | return nonseekable_open(inode, file); | 115 | return nonseekable_open(inode, file); |
106 | } | 116 | } |
107 | 117 | ||
@@ -122,18 +132,28 @@ static ssize_t orion5x_wdt_write(struct file *file, const char *data, | |||
122 | set_bit(WDT_OK_TO_CLOSE, &wdt_status); | 132 | set_bit(WDT_OK_TO_CLOSE, &wdt_status); |
123 | } | 133 | } |
124 | } | 134 | } |
125 | wdt_enable(); | 135 | orion5x_wdt_ping(); |
126 | } | 136 | } |
127 | return len; | 137 | return len; |
128 | } | 138 | } |
129 | 139 | ||
130 | static struct watchdog_info ident = { | 140 | static int orion5x_wdt_settimeout(int new_time) |
141 | { | ||
142 | if ((new_time <= 0) || (new_time > wdt_max_duration)) | ||
143 | return -EINVAL; | ||
144 | |||
145 | /* Set new watchdog time to be used when | ||
146 | * orion5x_wdt_enable() or orion5x_wdt_ping() is called. */ | ||
147 | heartbeat = new_time; | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static const struct watchdog_info ident = { | ||
131 | .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | | 152 | .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | |
132 | WDIOF_KEEPALIVEPING, | 153 | WDIOF_KEEPALIVEPING, |
133 | .identity = "Orion5x Watchdog", | 154 | .identity = "Orion5x Watchdog", |
134 | }; | 155 | }; |
135 | 156 | ||
136 | |||
137 | static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | 157 | static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, |
138 | unsigned long arg) | 158 | unsigned long arg) |
139 | { | 159 | { |
@@ -152,7 +172,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | |||
152 | break; | 172 | break; |
153 | 173 | ||
154 | case WDIOC_KEEPALIVE: | 174 | case WDIOC_KEEPALIVE: |
155 | wdt_enable(); | 175 | orion5x_wdt_ping(); |
156 | ret = 0; | 176 | ret = 0; |
157 | break; | 177 | break; |
158 | 178 | ||
@@ -161,12 +181,11 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | |||
161 | if (ret) | 181 | if (ret) |
162 | break; | 182 | break; |
163 | 183 | ||
164 | if (time <= 0 || time > wdt_max_duration) { | 184 | if (orion5x_wdt_settimeout(time)) { |
165 | ret = -EINVAL; | 185 | ret = -EINVAL; |
166 | break; | 186 | break; |
167 | } | 187 | } |
168 | heartbeat = time; | 188 | orion5x_wdt_ping(); |
169 | wdt_enable(); | ||
170 | /* Fall through */ | 189 | /* Fall through */ |
171 | 190 | ||
172 | case WDIOC_GETTIMEOUT: | 191 | case WDIOC_GETTIMEOUT: |
@@ -187,7 +206,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | |||
187 | static int orion5x_wdt_release(struct inode *inode, struct file *file) | 206 | static int orion5x_wdt_release(struct inode *inode, struct file *file) |
188 | { | 207 | { |
189 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) | 208 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) |
190 | wdt_disable(); | 209 | orion5x_wdt_disable(); |
191 | else | 210 | else |
192 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " | 211 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " |
193 | "timer will not stop\n"); | 212 | "timer will not stop\n"); |
@@ -230,7 +249,7 @@ static int __devinit orion5x_wdt_probe(struct platform_device *pdev) | |||
230 | orion5x_wdt_miscdev.parent = &pdev->dev; | 249 | orion5x_wdt_miscdev.parent = &pdev->dev; |
231 | 250 | ||
232 | wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; | 251 | wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; |
233 | if (heartbeat <= 0 || heartbeat > wdt_max_duration) | 252 | if (orion5x_wdt_settimeout(heartbeat)) |
234 | heartbeat = wdt_max_duration; | 253 | heartbeat = wdt_max_duration; |
235 | 254 | ||
236 | ret = misc_register(&orion5x_wdt_miscdev); | 255 | ret = misc_register(&orion5x_wdt_miscdev); |
@@ -247,7 +266,7 @@ static int __devexit orion5x_wdt_remove(struct platform_device *pdev) | |||
247 | int ret; | 266 | int ret; |
248 | 267 | ||
249 | if (test_bit(WDT_IN_USE, &wdt_status)) { | 268 | if (test_bit(WDT_IN_USE, &wdt_status)) { |
250 | wdt_disable(); | 269 | orion5x_wdt_disable(); |
251 | clear_bit(WDT_IN_USE, &wdt_status); | 270 | clear_bit(WDT_IN_USE, &wdt_status); |
252 | } | 271 | } |
253 | 272 | ||
@@ -258,9 +277,16 @@ static int __devexit orion5x_wdt_remove(struct platform_device *pdev) | |||
258 | return ret; | 277 | return ret; |
259 | } | 278 | } |
260 | 279 | ||
280 | static void orion5x_wdt_shutdown(struct platform_device *pdev) | ||
281 | { | ||
282 | if (test_bit(WDT_IN_USE, &wdt_status)) | ||
283 | orion5x_wdt_disable(); | ||
284 | } | ||
285 | |||
261 | static struct platform_driver orion5x_wdt_driver = { | 286 | static struct platform_driver orion5x_wdt_driver = { |
262 | .probe = orion5x_wdt_probe, | 287 | .probe = orion5x_wdt_probe, |
263 | .remove = __devexit_p(orion5x_wdt_remove), | 288 | .remove = __devexit_p(orion5x_wdt_remove), |
289 | .shutdown = orion5x_wdt_shutdown, | ||
264 | .driver = { | 290 | .driver = { |
265 | .owner = THIS_MODULE, | 291 | .owner = THIS_MODULE, |
266 | .name = "orion5x_wdt", | 292 | .name = "orion5x_wdt", |
@@ -285,10 +311,11 @@ MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>"); | |||
285 | MODULE_DESCRIPTION("Orion5x Processor Watchdog"); | 311 | MODULE_DESCRIPTION("Orion5x Processor Watchdog"); |
286 | 312 | ||
287 | module_param(heartbeat, int, 0); | 313 | module_param(heartbeat, int, 0); |
288 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds"); | 314 | MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds"); |
289 | 315 | ||
290 | module_param(nowayout, int, 0); | 316 | module_param(nowayout, int, 0); |
291 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | 317 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
318 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
292 | 319 | ||
293 | MODULE_LICENSE("GPL"); | 320 | MODULE_LICENSE("GPL"); |
294 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 321 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |