aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/omap_wdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/omap_wdt.c')
-rw-r--r--drivers/watchdog/omap_wdt.c132
1 files changed, 78 insertions, 54 deletions
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 9c389b16497f..7bcbb7f4745f 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -70,11 +70,14 @@ struct omap_wdt_dev {
70static void omap_wdt_ping(struct omap_wdt_dev *wdev) 70static void omap_wdt_ping(struct omap_wdt_dev *wdev)
71{ 71{
72 void __iomem *base = wdev->base; 72 void __iomem *base = wdev->base;
73
73 /* wait for posted write to complete */ 74 /* wait for posted write to complete */
74 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 75 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
75 cpu_relax(); 76 cpu_relax();
77
76 wdt_trgr_pattern = ~wdt_trgr_pattern; 78 wdt_trgr_pattern = ~wdt_trgr_pattern;
77 __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR)); 79 __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
80
78 /* wait for posted write to complete */ 81 /* wait for posted write to complete */
79 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 82 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
80 cpu_relax(); 83 cpu_relax();
@@ -83,12 +86,13 @@ static void omap_wdt_ping(struct omap_wdt_dev *wdev)
83 86
84static void omap_wdt_enable(struct omap_wdt_dev *wdev) 87static void omap_wdt_enable(struct omap_wdt_dev *wdev)
85{ 88{
86 void __iomem *base; 89 void __iomem *base = wdev->base;
87 base = wdev->base; 90
88 /* Sequence to enable the watchdog */ 91 /* Sequence to enable the watchdog */
89 __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR); 92 __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
90 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10) 93 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
91 cpu_relax(); 94 cpu_relax();
95
92 __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR); 96 __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
93 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10) 97 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
94 cpu_relax(); 98 cpu_relax();
@@ -96,12 +100,13 @@ static void omap_wdt_enable(struct omap_wdt_dev *wdev)
96 100
97static void omap_wdt_disable(struct omap_wdt_dev *wdev) 101static void omap_wdt_disable(struct omap_wdt_dev *wdev)
98{ 102{
99 void __iomem *base; 103 void __iomem *base = wdev->base;
100 base = wdev->base; 104
101 /* sequence required to disable watchdog */ 105 /* sequence required to disable watchdog */
102 __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */ 106 __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
103 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10) 107 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
104 cpu_relax(); 108 cpu_relax();
109
105 __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */ 110 __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
106 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10) 111 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
107 cpu_relax(); 112 cpu_relax();
@@ -119,12 +124,12 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
119static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) 124static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
120{ 125{
121 u32 pre_margin = GET_WLDR_VAL(timer_margin); 126 u32 pre_margin = GET_WLDR_VAL(timer_margin);
122 void __iomem *base; 127 void __iomem *base = wdev->base;
123 base = wdev->base;
124 128
125 /* just count up at 32 KHz */ 129 /* just count up at 32 KHz */
126 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) 130 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
127 cpu_relax(); 131 cpu_relax();
132
128 __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR); 133 __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
129 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) 134 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
130 cpu_relax(); 135 cpu_relax();
@@ -133,13 +138,11 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
133/* 138/*
134 * Allow only one task to hold it open 139 * Allow only one task to hold it open
135 */ 140 */
136
137static int omap_wdt_open(struct inode *inode, struct file *file) 141static int omap_wdt_open(struct inode *inode, struct file *file)
138{ 142{
139 struct omap_wdt_dev *wdev; 143 struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
140 void __iomem *base; 144 void __iomem *base = wdev->base;
141 wdev = platform_get_drvdata(omap_wdt_dev); 145
142 base = wdev->base;
143 if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users))) 146 if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
144 return -EBUSY; 147 return -EBUSY;
145 148
@@ -154,6 +157,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
154 /* initialize prescaler */ 157 /* initialize prescaler */
155 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) 158 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
156 cpu_relax(); 159 cpu_relax();
160
157 __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL); 161 __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
158 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) 162 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
159 cpu_relax(); 163 cpu_relax();
@@ -162,13 +166,14 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
162 166
163 omap_wdt_set_timeout(wdev); 167 omap_wdt_set_timeout(wdev);
164 omap_wdt_enable(wdev); 168 omap_wdt_enable(wdev);
169
165 return nonseekable_open(inode, file); 170 return nonseekable_open(inode, file);
166} 171}
167 172
168static int omap_wdt_release(struct inode *inode, struct file *file) 173static int omap_wdt_release(struct inode *inode, struct file *file)
169{ 174{
170 struct omap_wdt_dev *wdev; 175 struct omap_wdt_dev *wdev = file->private_data;
171 wdev = file->private_data; 176
172 /* 177 /*
173 * Shut off the timer unless NOWAYOUT is defined. 178 * Shut off the timer unless NOWAYOUT is defined.
174 */ 179 */
@@ -187,14 +192,15 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
187 printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); 192 printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
188#endif 193#endif
189 wdev->omap_wdt_users = 0; 194 wdev->omap_wdt_users = 0;
195
190 return 0; 196 return 0;
191} 197}
192 198
193static ssize_t omap_wdt_write(struct file *file, const char __user *data, 199static ssize_t omap_wdt_write(struct file *file, const char __user *data,
194 size_t len, loff_t *ppos) 200 size_t len, loff_t *ppos)
195{ 201{
196 struct omap_wdt_dev *wdev; 202 struct omap_wdt_dev *wdev = file->private_data;
197 wdev = file->private_data; 203
198 /* Refresh LOAD_TIME. */ 204 /* Refresh LOAD_TIME. */
199 if (len) { 205 if (len) {
200 spin_lock(&wdt_lock); 206 spin_lock(&wdt_lock);
@@ -214,6 +220,7 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
214 .options = WDIOF_SETTIMEOUT, 220 .options = WDIOF_SETTIMEOUT,
215 .firmware_version = 0, 221 .firmware_version = 0,
216 }; 222 };
223
217 wdev = file->private_data; 224 wdev = file->private_data;
218 225
219 switch (cmd) { 226 switch (cmd) {
@@ -262,31 +269,37 @@ static const struct file_operations omap_wdt_fops = {
262 .release = omap_wdt_release, 269 .release = omap_wdt_release,
263}; 270};
264 271
265
266static int __init omap_wdt_probe(struct platform_device *pdev) 272static int __init omap_wdt_probe(struct platform_device *pdev)
267{ 273{
268 struct resource *res, *mem; 274 struct resource *res, *mem;
269 int ret;
270 struct omap_wdt_dev *wdev; 275 struct omap_wdt_dev *wdev;
276 int ret;
271 277
272 /* reserve static register mappings */ 278 /* reserve static register mappings */
273 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 279 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
274 if (!res) 280 if (!res) {
275 return -ENOENT; 281 ret = -ENOENT;
282 goto err_get_resource;
283 }
276 284
277 if (omap_wdt_dev) 285 if (omap_wdt_dev) {
278 return -EBUSY; 286 ret = -EBUSY;
287 goto err_busy;
288 }
279 289
280 mem = request_mem_region(res->start, res->end - res->start + 1, 290 mem = request_mem_region(res->start, res->end - res->start + 1,
281 pdev->name); 291 pdev->name);
282 if (mem == NULL) 292 if (!mem) {
283 return -EBUSY; 293 ret = -EBUSY;
294 goto err_busy;
295 }
284 296
285 wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); 297 wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
286 if (!wdev) { 298 if (!wdev) {
287 ret = -ENOMEM; 299 ret = -ENOMEM;
288 goto fail; 300 goto err_kzalloc;
289 } 301 }
302
290 wdev->omap_wdt_users = 0; 303 wdev->omap_wdt_users = 0;
291 wdev->mem = mem; 304 wdev->mem = mem;
292 305
@@ -295,7 +308,7 @@ static int __init omap_wdt_probe(struct platform_device *pdev)
295 if (IS_ERR(wdev->armwdt_ck)) { 308 if (IS_ERR(wdev->armwdt_ck)) {
296 ret = PTR_ERR(wdev->armwdt_ck); 309 ret = PTR_ERR(wdev->armwdt_ck);
297 wdev->armwdt_ck = NULL; 310 wdev->armwdt_ck = NULL;
298 goto fail; 311 goto err_clk;
299 } 312 }
300 } 313 }
301 314
@@ -304,13 +317,13 @@ static int __init omap_wdt_probe(struct platform_device *pdev)
304 if (IS_ERR(wdev->mpu_wdt_ick)) { 317 if (IS_ERR(wdev->mpu_wdt_ick)) {
305 ret = PTR_ERR(wdev->mpu_wdt_ick); 318 ret = PTR_ERR(wdev->mpu_wdt_ick);
306 wdev->mpu_wdt_ick = NULL; 319 wdev->mpu_wdt_ick = NULL;
307 goto fail; 320 goto err_clk;
308 } 321 }
309 wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck"); 322 wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
310 if (IS_ERR(wdev->mpu_wdt_fck)) { 323 if (IS_ERR(wdev->mpu_wdt_fck)) {
311 ret = PTR_ERR(wdev->mpu_wdt_fck); 324 ret = PTR_ERR(wdev->mpu_wdt_fck);
312 wdev->mpu_wdt_fck = NULL; 325 wdev->mpu_wdt_fck = NULL;
313 goto fail; 326 goto err_clk;
314 } 327 }
315 } 328 }
316 329
@@ -319,19 +332,19 @@ static int __init omap_wdt_probe(struct platform_device *pdev)
319 if (IS_ERR(wdev->mpu_wdt_ick)) { 332 if (IS_ERR(wdev->mpu_wdt_ick)) {
320 ret = PTR_ERR(wdev->mpu_wdt_ick); 333 ret = PTR_ERR(wdev->mpu_wdt_ick);
321 wdev->mpu_wdt_ick = NULL; 334 wdev->mpu_wdt_ick = NULL;
322 goto fail; 335 goto err_clk;
323 } 336 }
324 wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck"); 337 wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
325 if (IS_ERR(wdev->mpu_wdt_fck)) { 338 if (IS_ERR(wdev->mpu_wdt_fck)) {
326 ret = PTR_ERR(wdev->mpu_wdt_fck); 339 ret = PTR_ERR(wdev->mpu_wdt_fck);
327 wdev->mpu_wdt_fck = NULL; 340 wdev->mpu_wdt_fck = NULL;
328 goto fail; 341 goto err_clk;
329 } 342 }
330 } 343 }
331 wdev->base = ioremap(res->start, res->end - res->start + 1); 344 wdev->base = ioremap(res->start, res->end - res->start + 1);
332 if (!wdev->base) { 345 if (!wdev->base) {
333 ret = -ENOMEM; 346 ret = -ENOMEM;
334 goto fail; 347 goto err_ioremap;
335 } 348 }
336 349
337 platform_set_drvdata(pdev, wdev); 350 platform_set_drvdata(pdev, wdev);
@@ -346,7 +359,7 @@ static int __init omap_wdt_probe(struct platform_device *pdev)
346 359
347 ret = misc_register(&(wdev->omap_wdt_miscdev)); 360 ret = misc_register(&(wdev->omap_wdt_miscdev));
348 if (ret) 361 if (ret)
349 goto fail; 362 goto err_misc;
350 363
351 pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", 364 pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
352 __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, 365 __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
@@ -359,28 +372,34 @@ static int __init omap_wdt_probe(struct platform_device *pdev)
359 372
360 return 0; 373 return 0;
361 374
362fail: 375err_misc:
363 if (wdev) { 376 platform_set_drvdata(pdev, NULL);
364 platform_set_drvdata(pdev, NULL); 377 iounmap(wdev->base);
365 if (wdev->armwdt_ck) 378
366 clk_put(wdev->armwdt_ck); 379err_ioremap:
367 if (wdev->mpu_wdt_ick) 380 wdev->base = NULL;
368 clk_put(wdev->mpu_wdt_ick); 381
369 if (wdev->mpu_wdt_fck) 382err_clk:
370 clk_put(wdev->mpu_wdt_fck); 383 if (wdev->armwdt_ck)
371 iounmap(wdev->base); 384 clk_put(wdev->armwdt_ck);
372 kfree(wdev); 385 if (wdev->mpu_wdt_ick)
373 } 386 clk_put(wdev->mpu_wdt_ick);
374 if (mem) { 387 if (wdev->mpu_wdt_fck)
375 release_mem_region(res->start, res->end - res->start + 1); 388 clk_put(wdev->mpu_wdt_fck);
376 } 389 kfree(wdev);
390
391err_kzalloc:
392 release_mem_region(res->start, res->end - res->start + 1);
393
394err_busy:
395err_get_resource:
396
377 return ret; 397 return ret;
378} 398}
379 399
380static void omap_wdt_shutdown(struct platform_device *pdev) 400static void omap_wdt_shutdown(struct platform_device *pdev)
381{ 401{
382 struct omap_wdt_dev *wdev; 402 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
383 wdev = platform_get_drvdata(pdev);
384 403
385 if (wdev->omap_wdt_users) 404 if (wdev->omap_wdt_users)
386 omap_wdt_disable(wdev); 405 omap_wdt_disable(wdev);
@@ -388,8 +407,7 @@ static void omap_wdt_shutdown(struct platform_device *pdev)
388 407
389static int omap_wdt_remove(struct platform_device *pdev) 408static int omap_wdt_remove(struct platform_device *pdev)
390{ 409{
391 struct omap_wdt_dev *wdev; 410 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
392 wdev = platform_get_drvdata(pdev);
393 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 411 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
394 412
395 if (!res) 413 if (!res)
@@ -398,14 +416,17 @@ static int omap_wdt_remove(struct platform_device *pdev)
398 misc_deregister(&(wdev->omap_wdt_miscdev)); 416 misc_deregister(&(wdev->omap_wdt_miscdev));
399 release_mem_region(res->start, res->end - res->start + 1); 417 release_mem_region(res->start, res->end - res->start + 1);
400 platform_set_drvdata(pdev, NULL); 418 platform_set_drvdata(pdev, NULL);
419
401 if (wdev->armwdt_ck) { 420 if (wdev->armwdt_ck) {
402 clk_put(wdev->armwdt_ck); 421 clk_put(wdev->armwdt_ck);
403 wdev->armwdt_ck = NULL; 422 wdev->armwdt_ck = NULL;
404 } 423 }
424
405 if (wdev->mpu_wdt_ick) { 425 if (wdev->mpu_wdt_ick) {
406 clk_put(wdev->mpu_wdt_ick); 426 clk_put(wdev->mpu_wdt_ick);
407 wdev->mpu_wdt_ick = NULL; 427 wdev->mpu_wdt_ick = NULL;
408 } 428 }
429
409 if (wdev->mpu_wdt_fck) { 430 if (wdev->mpu_wdt_fck) {
410 clk_put(wdev->mpu_wdt_fck); 431 clk_put(wdev->mpu_wdt_fck);
411 wdev->mpu_wdt_fck = NULL; 432 wdev->mpu_wdt_fck = NULL;
@@ -414,6 +435,7 @@ static int omap_wdt_remove(struct platform_device *pdev)
414 435
415 kfree(wdev); 436 kfree(wdev);
416 omap_wdt_dev = NULL; 437 omap_wdt_dev = NULL;
438
417 return 0; 439 return 0;
418} 440}
419 441
@@ -427,21 +449,23 @@ static int omap_wdt_remove(struct platform_device *pdev)
427 449
428static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) 450static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
429{ 451{
430 struct omap_wdt_dev *wdev; 452 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
431 wdev = platform_get_drvdata(pdev); 453
432 if (wdev->omap_wdt_users) 454 if (wdev->omap_wdt_users)
433 omap_wdt_disable(wdev); 455 omap_wdt_disable(wdev);
456
434 return 0; 457 return 0;
435} 458}
436 459
437static int omap_wdt_resume(struct platform_device *pdev) 460static int omap_wdt_resume(struct platform_device *pdev)
438{ 461{
439 struct omap_wdt_dev *wdev; 462 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
440 wdev = platform_get_drvdata(pdev); 463
441 if (wdev->omap_wdt_users) { 464 if (wdev->omap_wdt_users) {
442 omap_wdt_enable(wdev); 465 omap_wdt_enable(wdev);
443 omap_wdt_ping(wdev); 466 omap_wdt_ping(wdev);
444 } 467 }
468
445 return 0; 469 return 0;
446} 470}
447 471