aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/shwdt.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-05-10 02:07:53 -0400
committerPaul Mundt <lethal@linux-sh.org>2012-05-10 02:07:53 -0400
commit1950f499df4eacb5d89cf0151f5edda139b800f4 (patch)
tree25239fa0da5331b0178b67b0a060362909afd06e /drivers/watchdog/shwdt.c
parent40968126366219d11201257b5006878f939c1c5c (diff)
watchdog: shwdt: Conversion to watchdog core.
Fairly straightforward conversion to utilize watchdog core support. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/watchdog/shwdt.c')
-rw-r--r--drivers/watchdog/shwdt.c198
1 files changed, 44 insertions, 154 deletions
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index 74a261f36702..0beabf238d4f 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -27,12 +27,10 @@
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/miscdevice.h> 28#include <linux/miscdevice.h>
29#include <linux/watchdog.h> 29#include <linux/watchdog.h>
30#include <linux/ioport.h>
31#include <linux/fs.h> 30#include <linux/fs.h>
32#include <linux/mm.h> 31#include <linux/mm.h>
33#include <linux/slab.h> 32#include <linux/slab.h>
34#include <linux/io.h> 33#include <linux/io.h>
35#include <linux/uaccess.h>
36#include <asm/watchdog.h> 34#include <asm/watchdog.h>
37 35
38#define DRV_NAME "sh-wdt" 36#define DRV_NAME "sh-wdt"
@@ -67,8 +65,6 @@
67static int clock_division_ratio = WTCSR_CKS_4096; 65static int clock_division_ratio = WTCSR_CKS_4096;
68#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4)) 66#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4))
69 67
70static const struct watchdog_info sh_wdt_info;
71static struct platform_device *sh_wdt_dev;
72static DEFINE_SPINLOCK(shwdt_lock); 68static DEFINE_SPINLOCK(shwdt_lock);
73 69
74#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ 70#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
@@ -86,8 +82,9 @@ struct sh_wdt {
86 char expect_close; 82 char expect_close;
87}; 83};
88 84
89static void sh_wdt_start(struct sh_wdt *wdt) 85static int sh_wdt_start(struct watchdog_device *wdt_dev)
90{ 86{
87 struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
91 unsigned long flags; 88 unsigned long flags;
92 u8 csr; 89 u8 csr;
93 90
@@ -121,10 +118,13 @@ static void sh_wdt_start(struct sh_wdt *wdt)
121 sh_wdt_write_rstcsr(csr); 118 sh_wdt_write_rstcsr(csr);
122#endif 119#endif
123 spin_unlock_irqrestore(&shwdt_lock, flags); 120 spin_unlock_irqrestore(&shwdt_lock, flags);
121
122 return 0;
124} 123}
125 124
126static void sh_wdt_stop(struct sh_wdt *wdt) 125static int sh_wdt_stop(struct watchdog_device *wdt_dev)
127{ 126{
127 struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
128 unsigned long flags; 128 unsigned long flags;
129 u8 csr; 129 u8 csr;
130 130
@@ -137,18 +137,22 @@ static void sh_wdt_stop(struct sh_wdt *wdt)
137 sh_wdt_write_csr(csr); 137 sh_wdt_write_csr(csr);
138 138
139 spin_unlock_irqrestore(&shwdt_lock, flags); 139 spin_unlock_irqrestore(&shwdt_lock, flags);
140
141 return 0;
140} 142}
141 143
142static inline void sh_wdt_keepalive(struct sh_wdt *wdt) 144static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
143{ 145{
144 unsigned long flags; 146 unsigned long flags;
145 147
146 spin_lock_irqsave(&shwdt_lock, flags); 148 spin_lock_irqsave(&shwdt_lock, flags);
147 next_heartbeat = jiffies + (heartbeat * HZ); 149 next_heartbeat = jiffies + (heartbeat * HZ);
148 spin_unlock_irqrestore(&shwdt_lock, flags); 150 spin_unlock_irqrestore(&shwdt_lock, flags);
151
152 return 0;
149} 153}
150 154
151static int sh_wdt_set_heartbeat(int t) 155static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
152{ 156{
153 unsigned long flags; 157 unsigned long flags;
154 158
@@ -157,7 +161,9 @@ static int sh_wdt_set_heartbeat(int t)
157 161
158 spin_lock_irqsave(&shwdt_lock, flags); 162 spin_lock_irqsave(&shwdt_lock, flags);
159 heartbeat = t; 163 heartbeat = t;
164 wdt_dev->timeout = t;
160 spin_unlock_irqrestore(&shwdt_lock, flags); 165 spin_unlock_irqrestore(&shwdt_lock, flags);
166
161 return 0; 167 return 0;
162} 168}
163 169
@@ -183,123 +189,6 @@ static void sh_wdt_ping(unsigned long data)
183 spin_unlock_irqrestore(&shwdt_lock, flags); 189 spin_unlock_irqrestore(&shwdt_lock, flags);
184} 190}
185 191
186static int sh_wdt_open(struct inode *inode, struct file *file)
187{
188 struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
189
190 if (test_and_set_bit(0, &wdt->enabled))
191 return -EBUSY;
192 if (nowayout)
193 __module_get(THIS_MODULE);
194
195 file->private_data = wdt;
196
197 sh_wdt_start(wdt);
198
199 return nonseekable_open(inode, file);
200}
201
202static int sh_wdt_close(struct inode *inode, struct file *file)
203{
204 struct sh_wdt *wdt = file->private_data;
205
206 if (wdt->expect_close == 42) {
207 sh_wdt_stop(wdt);
208 } else {
209 dev_crit(wdt->dev, "Unexpected close, not "
210 "stopping watchdog!\n");
211 sh_wdt_keepalive(wdt);
212 }
213
214 clear_bit(0, &wdt->enabled);
215 wdt->expect_close = 0;
216
217 return 0;
218}
219
220static ssize_t sh_wdt_write(struct file *file, const char *buf,
221 size_t count, loff_t *ppos)
222{
223 struct sh_wdt *wdt = file->private_data;
224
225 if (count) {
226 if (!nowayout) {
227 size_t i;
228
229 wdt->expect_close = 0;
230
231 for (i = 0; i != count; i++) {
232 char c;
233 if (get_user(c, buf + i))
234 return -EFAULT;
235 if (c == 'V')
236 wdt->expect_close = 42;
237 }
238 }
239 sh_wdt_keepalive(wdt);
240 }
241
242 return count;
243}
244
245static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
246 unsigned long arg)
247{
248 struct sh_wdt *wdt = file->private_data;
249 int new_heartbeat;
250 int options, retval = -EINVAL;
251
252 switch (cmd) {
253 case WDIOC_GETSUPPORT:
254 return copy_to_user((struct watchdog_info *)arg,
255 &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
256 case WDIOC_GETSTATUS:
257 case WDIOC_GETBOOTSTATUS:
258 return put_user(0, (int *)arg);
259 case WDIOC_SETOPTIONS:
260 if (get_user(options, (int *)arg))
261 return -EFAULT;
262
263 if (options & WDIOS_DISABLECARD) {
264 sh_wdt_stop(wdt);
265 retval = 0;
266 }
267
268 if (options & WDIOS_ENABLECARD) {
269 sh_wdt_start(wdt);
270 retval = 0;
271 }
272
273 return retval;
274 case WDIOC_KEEPALIVE:
275 sh_wdt_keepalive(wdt);
276 return 0;
277 case WDIOC_SETTIMEOUT:
278 if (get_user(new_heartbeat, (int *)arg))
279 return -EFAULT;
280
281 if (sh_wdt_set_heartbeat(new_heartbeat))
282 return -EINVAL;
283
284 sh_wdt_keepalive(wdt);
285 /* Fall */
286 case WDIOC_GETTIMEOUT:
287 return put_user(heartbeat, (int *)arg);
288 default:
289 return -ENOTTY;
290 }
291 return 0;
292}
293
294static const struct file_operations sh_wdt_fops = {
295 .owner = THIS_MODULE,
296 .llseek = no_llseek,
297 .write = sh_wdt_write,
298 .unlocked_ioctl = sh_wdt_ioctl,
299 .open = sh_wdt_open,
300 .release = sh_wdt_close,
301};
302
303static const struct watchdog_info sh_wdt_info = { 192static const struct watchdog_info sh_wdt_info = {
304 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | 193 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
305 WDIOF_MAGICCLOSE, 194 WDIOF_MAGICCLOSE,
@@ -307,10 +196,17 @@ static const struct watchdog_info sh_wdt_info = {
307 .identity = "SH WDT", 196 .identity = "SH WDT",
308}; 197};
309 198
310static struct miscdevice sh_wdt_miscdev = { 199static const struct watchdog_ops sh_wdt_ops = {
311 .minor = WATCHDOG_MINOR, 200 .owner = THIS_MODULE,
312 .name = "watchdog", 201 .start = sh_wdt_start,
313 .fops = &sh_wdt_fops, 202 .stop = sh_wdt_stop,
203 .ping = sh_wdt_keepalive,
204 .set_timeout = sh_wdt_set_heartbeat,
205};
206
207static struct watchdog_device sh_wdt_dev = {
208 .info = &sh_wdt_info,
209 .ops = &sh_wdt_ops,
314}; 210};
315 211
316static int __devinit sh_wdt_probe(struct platform_device *pdev) 212static int __devinit sh_wdt_probe(struct platform_device *pdev)
@@ -348,13 +244,25 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
348 goto out_err; 244 goto out_err;
349 } 245 }
350 246
351 sh_wdt_miscdev.parent = wdt->dev; 247 rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
248 if (unlikely(rc)) {
249 /* Default timeout if invalid */
250 sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
251
252 dev_warn(&pdev->dev,
253 "heartbeat value must be 1<=x<=3600, using %d\n",
254 sh_wdt_dev.timeout);
255 }
256
257 dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
258 sh_wdt_dev.timeout, nowayout);
352 259
353 rc = misc_register(&sh_wdt_miscdev); 260 watchdog_set_nowayout(&sh_wdt_dev, nowayout);
261 watchdog_set_drvdata(&sh_wdt_dev, wdt);
262
263 rc = watchdog_register_device(&sh_wdt_dev);
354 if (unlikely(rc)) { 264 if (unlikely(rc)) {
355 dev_err(&pdev->dev, 265 dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
356 "Can't register miscdev on minor=%d (err=%d)\n",
357 sh_wdt_miscdev.minor, rc);
358 goto out_unmap; 266 goto out_unmap;
359 } 267 }
360 268
@@ -364,7 +272,6 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
364 wdt->timer.expires = next_ping_period(clock_division_ratio); 272 wdt->timer.expires = next_ping_period(clock_division_ratio);
365 273
366 platform_set_drvdata(pdev, wdt); 274 platform_set_drvdata(pdev, wdt);
367 sh_wdt_dev = pdev;
368 275
369 dev_info(&pdev->dev, "initialized.\n"); 276 dev_info(&pdev->dev, "initialized.\n");
370 277
@@ -387,9 +294,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev)
387 294
388 platform_set_drvdata(pdev, NULL); 295 platform_set_drvdata(pdev, NULL);
389 296
390 misc_deregister(&sh_wdt_miscdev); 297 watchdog_unregister_device(&sh_wdt_dev);
391
392 sh_wdt_dev = NULL;
393 298
394 devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); 299 devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
395 devm_iounmap(&pdev->dev, wdt->base); 300 devm_iounmap(&pdev->dev, wdt->base);
@@ -400,9 +305,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev)
400 305
401static void sh_wdt_shutdown(struct platform_device *pdev) 306static void sh_wdt_shutdown(struct platform_device *pdev)
402{ 307{
403 struct sh_wdt *wdt = platform_get_drvdata(pdev); 308 sh_wdt_stop(&sh_wdt_dev);
404
405 sh_wdt_stop(wdt);
406} 309}
407 310
408static struct platform_driver sh_wdt_driver = { 311static struct platform_driver sh_wdt_driver = {
@@ -418,8 +321,6 @@ static struct platform_driver sh_wdt_driver = {
418 321
419static int __init sh_wdt_init(void) 322static int __init sh_wdt_init(void)
420{ 323{
421 int rc;
422
423 if (unlikely(clock_division_ratio < 0x5 || 324 if (unlikely(clock_division_ratio < 0x5 ||
424 clock_division_ratio > 0x7)) { 325 clock_division_ratio > 0x7)) {
425 clock_division_ratio = WTCSR_CKS_4096; 326 clock_division_ratio = WTCSR_CKS_4096;
@@ -428,17 +329,6 @@ static int __init sh_wdt_init(void)
428 clock_division_ratio); 329 clock_division_ratio);
429 } 330 }
430 331
431 rc = sh_wdt_set_heartbeat(heartbeat);
432 if (unlikely(rc)) {
433 heartbeat = WATCHDOG_HEARTBEAT;
434
435 pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
436 heartbeat);
437 }
438
439 pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
440 heartbeat, nowayout);
441
442 return platform_driver_register(&sh_wdt_driver); 332 return platform_driver_register(&sh_wdt_driver);
443} 333}
444 334