aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/sp805_wdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/sp805_wdt.c')
-rw-r--r--drivers/watchdog/sp805_wdt.c111
1 files changed, 67 insertions, 44 deletions
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 3ff9e47bd218..bbb170e50055 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -25,6 +25,7 @@
25#include <linux/miscdevice.h> 25#include <linux/miscdevice.h>
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/moduleparam.h> 27#include <linux/moduleparam.h>
28#include <linux/pm.h>
28#include <linux/slab.h> 29#include <linux/slab.h>
29#include <linux/spinlock.h> 30#include <linux/spinlock.h>
30#include <linux/types.h> 31#include <linux/types.h>
@@ -55,14 +56,13 @@
55 56
56/** 57/**
57 * struct sp805_wdt: sp805 wdt device structure 58 * struct sp805_wdt: sp805 wdt device structure
58 * 59 * @lock: spin lock protecting dev structure and io access
59 * lock: spin lock protecting dev structure and io access 60 * @base: base address of wdt
60 * base: base address of wdt 61 * @clk: clock structure of wdt
61 * clk: clock structure of wdt 62 * @adev: amba device structure of wdt
62 * dev: amba device structure of wdt 63 * @status: current status of wdt
63 * status: current status of wdt 64 * @load_val: load value to be set for current timeout
64 * load_val: load value to be set for current timeout 65 * @timeout: current programmed timeout
65 * timeout: current programmed timeout
66 */ 66 */
67struct sp805_wdt { 67struct sp805_wdt {
68 spinlock_t lock; 68 spinlock_t lock;
@@ -78,7 +78,7 @@ struct sp805_wdt {
78 78
79/* local variables */ 79/* local variables */
80static struct sp805_wdt *wdt; 80static struct sp805_wdt *wdt;
81static int nowayout = WATCHDOG_NOWAYOUT; 81static bool nowayout = WATCHDOG_NOWAYOUT;
82 82
83/* This routine finds load value that will reset system in required timout */ 83/* This routine finds load value that will reset system in required timout */
84static void wdt_setload(unsigned int timeout) 84static void wdt_setload(unsigned int timeout)
@@ -113,10 +113,10 @@ static u32 wdt_timeleft(void)
113 rate = clk_get_rate(wdt->clk); 113 rate = clk_get_rate(wdt->clk);
114 114
115 spin_lock(&wdt->lock); 115 spin_lock(&wdt->lock);
116 load = readl(wdt->base + WDTVALUE); 116 load = readl_relaxed(wdt->base + WDTVALUE);
117 117
118 /*If the interrupt is inactive then time left is WDTValue + WDTLoad. */ 118 /*If the interrupt is inactive then time left is WDTValue + WDTLoad. */
119 if (!(readl(wdt->base + WDTRIS) & INT_MASK)) 119 if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK))
120 load += wdt->load_val + 1; 120 load += wdt->load_val + 1;
121 spin_unlock(&wdt->lock); 121 spin_unlock(&wdt->lock);
122 122
@@ -128,14 +128,14 @@ static void wdt_enable(void)
128{ 128{
129 spin_lock(&wdt->lock); 129 spin_lock(&wdt->lock);
130 130
131 writel(UNLOCK, wdt->base + WDTLOCK); 131 writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
132 writel(wdt->load_val, wdt->base + WDTLOAD); 132 writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
133 writel(INT_MASK, wdt->base + WDTINTCLR); 133 writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
134 writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL); 134 writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
135 writel(LOCK, wdt->base + WDTLOCK); 135 writel_relaxed(LOCK, wdt->base + WDTLOCK);
136 136
137 /* Flush posted writes. */ 137 /* Flush posted writes. */
138 readl(wdt->base + WDTLOCK); 138 readl_relaxed(wdt->base + WDTLOCK);
139 spin_unlock(&wdt->lock); 139 spin_unlock(&wdt->lock);
140} 140}
141 141
@@ -144,12 +144,12 @@ static void wdt_disable(void)
144{ 144{
145 spin_lock(&wdt->lock); 145 spin_lock(&wdt->lock);
146 146
147 writel(UNLOCK, wdt->base + WDTLOCK); 147 writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
148 writel(0, wdt->base + WDTCONTROL); 148 writel_relaxed(0, wdt->base + WDTCONTROL);
149 writel(LOCK, wdt->base + WDTLOCK); 149 writel_relaxed(LOCK, wdt->base + WDTLOCK);
150 150
151 /* Flush posted writes. */ 151 /* Flush posted writes. */
152 readl(wdt->base + WDTLOCK); 152 readl_relaxed(wdt->base + WDTLOCK);
153 spin_unlock(&wdt->lock); 153 spin_unlock(&wdt->lock);
154} 154}
155 155
@@ -285,32 +285,33 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
285{ 285{
286 int ret = 0; 286 int ret = 0;
287 287
288 if (!request_mem_region(adev->res.start, resource_size(&adev->res), 288 if (!devm_request_mem_region(&adev->dev, adev->res.start,
289 "sp805_wdt")) { 289 resource_size(&adev->res), "sp805_wdt")) {
290 dev_warn(&adev->dev, "Failed to get memory region resource\n"); 290 dev_warn(&adev->dev, "Failed to get memory region resource\n");
291 ret = -ENOENT; 291 ret = -ENOENT;
292 goto err; 292 goto err;
293 } 293 }
294 294
295 wdt = kzalloc(sizeof(*wdt), GFP_KERNEL); 295 wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
296 if (!wdt) { 296 if (!wdt) {
297 dev_warn(&adev->dev, "Kzalloc failed\n"); 297 dev_warn(&adev->dev, "Kzalloc failed\n");
298 ret = -ENOMEM; 298 ret = -ENOMEM;
299 goto err_kzalloc; 299 goto err;
300 }
301
302 wdt->base = devm_ioremap(&adev->dev, adev->res.start,
303 resource_size(&adev->res));
304 if (!wdt->base) {
305 ret = -ENOMEM;
306 dev_warn(&adev->dev, "ioremap fail\n");
307 goto err;
300 } 308 }
301 309
302 wdt->clk = clk_get(&adev->dev, NULL); 310 wdt->clk = clk_get(&adev->dev, NULL);
303 if (IS_ERR(wdt->clk)) { 311 if (IS_ERR(wdt->clk)) {
304 dev_warn(&adev->dev, "Clock not found\n"); 312 dev_warn(&adev->dev, "Clock not found\n");
305 ret = PTR_ERR(wdt->clk); 313 ret = PTR_ERR(wdt->clk);
306 goto err_clk_get; 314 goto err;
307 }
308
309 wdt->base = ioremap(adev->res.start, resource_size(&adev->res));
310 if (!wdt->base) {
311 ret = -ENOMEM;
312 dev_warn(&adev->dev, "ioremap fail\n");
313 goto err_ioremap;
314 } 315 }
315 316
316 wdt->adev = adev; 317 wdt->adev = adev;
@@ -327,14 +328,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
327 return 0; 328 return 0;
328 329
329err_misc_register: 330err_misc_register:
330 iounmap(wdt->base);
331err_ioremap:
332 clk_put(wdt->clk); 331 clk_put(wdt->clk);
333err_clk_get:
334 kfree(wdt);
335 wdt = NULL;
336err_kzalloc:
337 release_mem_region(adev->res.start, resource_size(&adev->res));
338err: 332err:
339 dev_err(&adev->dev, "Probe Failed!!!\n"); 333 dev_err(&adev->dev, "Probe Failed!!!\n");
340 return ret; 334 return ret;
@@ -343,14 +337,42 @@ err:
343static int __devexit sp805_wdt_remove(struct amba_device *adev) 337static int __devexit sp805_wdt_remove(struct amba_device *adev)
344{ 338{
345 misc_deregister(&sp805_wdt_miscdev); 339 misc_deregister(&sp805_wdt_miscdev);
346 iounmap(wdt->base);
347 clk_put(wdt->clk); 340 clk_put(wdt->clk);
348 kfree(wdt);
349 release_mem_region(adev->res.start, resource_size(&adev->res));
350 341
351 return 0; 342 return 0;
352} 343}
353 344
345#ifdef CONFIG_PM
346static int sp805_wdt_suspend(struct device *dev)
347{
348 if (test_bit(WDT_BUSY, &wdt->status)) {
349 wdt_disable();
350 clk_disable(wdt->clk);
351 }
352
353 return 0;
354}
355
356static int sp805_wdt_resume(struct device *dev)
357{
358 int ret = 0;
359
360 if (test_bit(WDT_BUSY, &wdt->status)) {
361 ret = clk_enable(wdt->clk);
362 if (ret) {
363 dev_err(dev, "clock enable fail");
364 return ret;
365 }
366 wdt_enable();
367 }
368
369 return ret;
370}
371#endif /* CONFIG_PM */
372
373static SIMPLE_DEV_PM_OPS(sp805_wdt_dev_pm_ops, sp805_wdt_suspend,
374 sp805_wdt_resume);
375
354static struct amba_id sp805_wdt_ids[] = { 376static struct amba_id sp805_wdt_ids[] = {
355 { 377 {
356 .id = 0x00141805, 378 .id = 0x00141805,
@@ -364,6 +386,7 @@ MODULE_DEVICE_TABLE(amba, sp805_wdt_ids);
364static struct amba_driver sp805_wdt_driver = { 386static struct amba_driver sp805_wdt_driver = {
365 .drv = { 387 .drv = {
366 .name = MODULE_NAME, 388 .name = MODULE_NAME,
389 .pm = &sp805_wdt_dev_pm_ops,
367 }, 390 },
368 .id_table = sp805_wdt_ids, 391 .id_table = sp805_wdt_ids,
369 .probe = sp805_wdt_probe, 392 .probe = sp805_wdt_probe,
@@ -372,7 +395,7 @@ static struct amba_driver sp805_wdt_driver = {
372 395
373module_amba_driver(sp805_wdt_driver); 396module_amba_driver(sp805_wdt_driver);
374 397
375module_param(nowayout, int, 0); 398module_param(nowayout, bool, 0);
376MODULE_PARM_DESC(nowayout, 399MODULE_PARM_DESC(nowayout,
377 "Set to 1 to keep watchdog running after device release"); 400 "Set to 1 to keep watchdog running after device release");
378 401