diff options
Diffstat (limited to 'drivers/watchdog/orion5x_wdt.c')
-rw-r--r-- | drivers/watchdog/orion5x_wdt.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c index b64ae1a17832..e81441f103dd 100644 --- a/drivers/watchdog/orion5x_wdt.c +++ b/drivers/watchdog/orion5x_wdt.c | |||
@@ -16,11 +16,13 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/miscdevice.h> | 18 | #include <linux/miscdevice.h> |
19 | #include <linux/platform_device.h> | ||
19 | #include <linux/watchdog.h> | 20 | #include <linux/watchdog.h> |
20 | #include <linux/init.h> | 21 | #include <linux/init.h> |
21 | #include <linux/uaccess.h> | 22 | #include <linux/uaccess.h> |
22 | #include <linux/io.h> | 23 | #include <linux/io.h> |
23 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <plat/orion5x_wdt.h> | ||
24 | 26 | ||
25 | /* | 27 | /* |
26 | * Watchdog timer block registers. | 28 | * Watchdog timer block registers. |
@@ -29,13 +31,14 @@ | |||
29 | #define WDT_EN 0x0010 | 31 | #define WDT_EN 0x0010 |
30 | #define WDT_VAL (TIMER_VIRT_BASE + 0x0024) | 32 | #define WDT_VAL (TIMER_VIRT_BASE + 0x0024) |
31 | 33 | ||
32 | #define ORION5X_TCLK 166666667 | 34 | #define WDT_MAX_CYCLE_COUNT 0xffffffff |
33 | #define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK) | ||
34 | #define WDT_IN_USE 0 | 35 | #define WDT_IN_USE 0 |
35 | #define WDT_OK_TO_CLOSE 1 | 36 | #define WDT_OK_TO_CLOSE 1 |
36 | 37 | ||
37 | static int nowayout = WATCHDOG_NOWAYOUT; | 38 | static int nowayout = WATCHDOG_NOWAYOUT; |
38 | static int heartbeat = WDT_MAX_DURATION; /* (seconds) */ | 39 | static int heartbeat = -1; /* module parameter (seconds) */ |
40 | static unsigned int wdt_max_duration; /* (seconds) */ | ||
41 | static unsigned int wdt_tclk; | ||
39 | static unsigned long wdt_status; | 42 | static unsigned long wdt_status; |
40 | static spinlock_t wdt_lock; | 43 | static spinlock_t wdt_lock; |
41 | 44 | ||
@@ -46,7 +49,7 @@ static void wdt_enable(void) | |||
46 | spin_lock(&wdt_lock); | 49 | spin_lock(&wdt_lock); |
47 | 50 | ||
48 | /* Set watchdog duration */ | 51 | /* Set watchdog duration */ |
49 | writel(ORION5X_TCLK * heartbeat, WDT_VAL); | 52 | writel(wdt_tclk * heartbeat, WDT_VAL); |
50 | 53 | ||
51 | /* Clear watchdog timer interrupt */ | 54 | /* Clear watchdog timer interrupt */ |
52 | reg = readl(BRIDGE_CAUSE); | 55 | reg = readl(BRIDGE_CAUSE); |
@@ -88,7 +91,7 @@ static void wdt_disable(void) | |||
88 | static int orion5x_wdt_get_timeleft(int *time_left) | 91 | static int orion5x_wdt_get_timeleft(int *time_left) |
89 | { | 92 | { |
90 | spin_lock(&wdt_lock); | 93 | spin_lock(&wdt_lock); |
91 | *time_left = readl(WDT_VAL) / ORION5X_TCLK; | 94 | *time_left = readl(WDT_VAL) / wdt_tclk; |
92 | spin_unlock(&wdt_lock); | 95 | spin_unlock(&wdt_lock); |
93 | return 0; | 96 | return 0; |
94 | } | 97 | } |
@@ -158,7 +161,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | |||
158 | if (ret) | 161 | if (ret) |
159 | break; | 162 | break; |
160 | 163 | ||
161 | if (time <= 0 || time > WDT_MAX_DURATION) { | 164 | if (time <= 0 || time > wdt_max_duration) { |
162 | ret = -EINVAL; | 165 | ret = -EINVAL; |
163 | break; | 166 | break; |
164 | } | 167 | } |
@@ -210,23 +213,69 @@ static struct miscdevice orion5x_wdt_miscdev = { | |||
210 | .fops = &orion5x_wdt_fops, | 213 | .fops = &orion5x_wdt_fops, |
211 | }; | 214 | }; |
212 | 215 | ||
213 | static int __init orion5x_wdt_init(void) | 216 | static int __devinit orion5x_wdt_probe(struct platform_device *pdev) |
214 | { | 217 | { |
218 | struct orion5x_wdt_platform_data *pdata = pdev->dev.platform_data; | ||
215 | int ret; | 219 | int ret; |
216 | 220 | ||
217 | spin_lock_init(&wdt_lock); | 221 | if (pdata) { |
222 | wdt_tclk = pdata->tclk; | ||
223 | } else { | ||
224 | printk(KERN_ERR "Orion5x Watchdog misses platform data\n"); | ||
225 | return -ENODEV; | ||
226 | } | ||
227 | |||
228 | if (orion5x_wdt_miscdev.parent) | ||
229 | return -EBUSY; | ||
230 | orion5x_wdt_miscdev.parent = &pdev->dev; | ||
231 | |||
232 | wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; | ||
233 | if (heartbeat <= 0 || heartbeat > wdt_max_duration) | ||
234 | heartbeat = wdt_max_duration; | ||
218 | 235 | ||
219 | ret = misc_register(&orion5x_wdt_miscdev); | 236 | ret = misc_register(&orion5x_wdt_miscdev); |
220 | if (ret == 0) | 237 | if (ret) |
221 | printk("Orion5x Watchdog Timer: heartbeat %d sec\n", | 238 | return ret; |
222 | heartbeat); | 239 | |
240 | printk(KERN_INFO "Orion5x Watchdog Timer: Initial timeout %d sec%s\n", | ||
241 | heartbeat, nowayout ? ", nowayout" : ""); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int __devexit orion5x_wdt_remove(struct platform_device *pdev) | ||
246 | { | ||
247 | int ret; | ||
248 | |||
249 | if (test_bit(WDT_IN_USE, &wdt_status)) { | ||
250 | wdt_disable(); | ||
251 | clear_bit(WDT_IN_USE, &wdt_status); | ||
252 | } | ||
253 | |||
254 | ret = misc_deregister(&orion5x_wdt_miscdev); | ||
255 | if (!ret) | ||
256 | orion5x_wdt_miscdev.parent = NULL; | ||
223 | 257 | ||
224 | return ret; | 258 | return ret; |
225 | } | 259 | } |
226 | 260 | ||
261 | static struct platform_driver orion5x_wdt_driver = { | ||
262 | .probe = orion5x_wdt_probe, | ||
263 | .remove = __devexit_p(orion5x_wdt_remove), | ||
264 | .driver = { | ||
265 | .owner = THIS_MODULE, | ||
266 | .name = "orion5x_wdt", | ||
267 | }, | ||
268 | }; | ||
269 | |||
270 | static int __init orion5x_wdt_init(void) | ||
271 | { | ||
272 | spin_lock_init(&wdt_lock); | ||
273 | return platform_driver_register(&orion5x_wdt_driver); | ||
274 | } | ||
275 | |||
227 | static void __exit orion5x_wdt_exit(void) | 276 | static void __exit orion5x_wdt_exit(void) |
228 | { | 277 | { |
229 | misc_deregister(&orion5x_wdt_miscdev); | 278 | platform_driver_unregister(&orion5x_wdt_driver); |
230 | } | 279 | } |
231 | 280 | ||
232 | module_init(orion5x_wdt_init); | 281 | module_init(orion5x_wdt_init); |
@@ -236,8 +285,7 @@ MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>"); | |||
236 | MODULE_DESCRIPTION("Orion5x Processor Watchdog"); | 285 | MODULE_DESCRIPTION("Orion5x Processor Watchdog"); |
237 | 286 | ||
238 | module_param(heartbeat, int, 0); | 287 | module_param(heartbeat, int, 0); |
239 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is " | 288 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds"); |
240 | __MODULE_STRING(WDT_MAX_DURATION) ")"); | ||
241 | 289 | ||
242 | module_param(nowayout, int, 0); | 290 | module_param(nowayout, int, 0); |
243 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | 291 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); |