aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/orion5x_wdt.c57
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;
42static unsigned long wdt_status; 42static unsigned long wdt_status;
43static spinlock_t wdt_lock; 43static spinlock_t wdt_lock;
44 44
45static void wdt_enable(void) 45static 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
55static 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
72static void wdt_disable(void) 82static 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
130static struct watchdog_info ident = { 140static 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
151static 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
137static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, 157static 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,
187static int orion5x_wdt_release(struct inode *inode, struct file *file) 206static 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
280static void orion5x_wdt_shutdown(struct platform_device *pdev)
281{
282 if (test_bit(WDT_IN_USE, &wdt_status))
283 orion5x_wdt_disable();
284}
285
261static struct platform_driver orion5x_wdt_driver = { 286static 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>");
285MODULE_DESCRIPTION("Orion5x Processor Watchdog"); 311MODULE_DESCRIPTION("Orion5x Processor Watchdog");
286 312
287module_param(heartbeat, int, 0); 313module_param(heartbeat, int, 0);
288MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds"); 314MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
289 315
290module_param(nowayout, int, 0); 316module_param(nowayout, int, 0);
291MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); 317MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
318 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
292 319
293MODULE_LICENSE("GPL"); 320MODULE_LICENSE("GPL");
294MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 321MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);