aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAaro Koskinen <aaro.koskinen@iki.fi>2012-10-10 16:23:32 -0400
committerWim Van Sebroeck <wim@iguana.be>2012-12-19 16:24:55 -0500
commit67c0f55468443ef8a1edc6ee92f9a92e4915be24 (patch)
tree812ce326687b4ce68cd6efa07da6143e2a2b9e92 /drivers
parentcf13a84d174947df4bb809edfb4887393642303e (diff)
watchdog: omap_wdt: convert to new watchdog core
Convert omap_wdt to new watchdog core. On OMAP boards, there are usually multiple watchdogs. Since the new watchdog core supports multiple watchdogs, all watchdog drivers used on OMAP should be converted. The legacy watchdog device node is still created, so this should not break existing users. Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi> Tested-by: Jarkko Nikula <jarkko.nikula@jollamobile.com> Tested-by: Lokesh Vutla <lokeshvutla@ti.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/omap_wdt.c260
2 files changed, 112 insertions, 149 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b19465c15091..aecce5c8cf11 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -232,6 +232,7 @@ config EP93XX_WATCHDOG
232config OMAP_WATCHDOG 232config OMAP_WATCHDOG
233 tristate "OMAP Watchdog" 233 tristate "OMAP Watchdog"
234 depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS 234 depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
235 select WATCHDOG_CORE
235 help 236 help
236 Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' 237 Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y'
237 here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer. 238 here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3e3ebbc83faf..89db92d10ade 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -31,42 +31,34 @@
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/types.h> 32#include <linux/types.h>
33#include <linux/kernel.h> 33#include <linux/kernel.h>
34#include <linux/fs.h>
35#include <linux/mm.h> 34#include <linux/mm.h>
36#include <linux/miscdevice.h>
37#include <linux/watchdog.h> 35#include <linux/watchdog.h>
38#include <linux/reboot.h> 36#include <linux/reboot.h>
39#include <linux/init.h> 37#include <linux/init.h>
40#include <linux/err.h> 38#include <linux/err.h>
41#include <linux/platform_device.h> 39#include <linux/platform_device.h>
42#include <linux/moduleparam.h> 40#include <linux/moduleparam.h>
43#include <linux/bitops.h>
44#include <linux/io.h> 41#include <linux/io.h>
45#include <linux/uaccess.h>
46#include <linux/slab.h> 42#include <linux/slab.h>
47#include <linux/pm_runtime.h> 43#include <linux/pm_runtime.h>
48#include <linux/platform_data/omap-wd-timer.h> 44#include <linux/platform_data/omap-wd-timer.h>
49 45
50#include "omap_wdt.h" 46#include "omap_wdt.h"
51 47
52static struct platform_device *omap_wdt_dev;
53
54static unsigned timer_margin; 48static unsigned timer_margin;
55module_param(timer_margin, uint, 0); 49module_param(timer_margin, uint, 0);
56MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); 50MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
57 51
58static unsigned int wdt_trgr_pattern = 0x1234;
59static DEFINE_SPINLOCK(wdt_lock);
60
61struct omap_wdt_dev { 52struct omap_wdt_dev {
62 void __iomem *base; /* physical */ 53 void __iomem *base; /* physical */
63 struct device *dev; 54 struct device *dev;
64 int omap_wdt_users; 55 bool omap_wdt_users;
65 struct resource *mem; 56 struct resource *mem;
66 struct miscdevice omap_wdt_miscdev; 57 int wdt_trgr_pattern;
58 struct mutex lock; /* to avoid races with PM */
67}; 59};
68 60
69static void omap_wdt_ping(struct omap_wdt_dev *wdev) 61static void omap_wdt_reload(struct omap_wdt_dev *wdev)
70{ 62{
71 void __iomem *base = wdev->base; 63 void __iomem *base = wdev->base;
72 64
@@ -74,8 +66,8 @@ static void omap_wdt_ping(struct omap_wdt_dev *wdev)
74 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 66 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
75 cpu_relax(); 67 cpu_relax();
76 68
77 wdt_trgr_pattern = ~wdt_trgr_pattern; 69 wdev->wdt_trgr_pattern = ~wdev->wdt_trgr_pattern;
78 __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR)); 70 __raw_writel(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
79 71
80 /* wait for posted write to complete */ 72 /* wait for posted write to complete */
81 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 73 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
@@ -111,18 +103,10 @@ static void omap_wdt_disable(struct omap_wdt_dev *wdev)
111 cpu_relax(); 103 cpu_relax();
112} 104}
113 105
114static void omap_wdt_adjust_timeout(unsigned new_timeout) 106static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
115{ 107 unsigned int timeout)
116 if (new_timeout < TIMER_MARGIN_MIN)
117 new_timeout = TIMER_MARGIN_DEFAULT;
118 if (new_timeout > TIMER_MARGIN_MAX)
119 new_timeout = TIMER_MARGIN_MAX;
120 timer_margin = new_timeout;
121}
122
123static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
124{ 108{
125 u32 pre_margin = GET_WLDR_VAL(timer_margin); 109 u32 pre_margin = GET_WLDR_VAL(timeout);
126 void __iomem *base = wdev->base; 110 void __iomem *base = wdev->base;
127 111
128 /* just count up at 32 KHz */ 112 /* just count up at 32 KHz */
@@ -134,16 +118,14 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
134 cpu_relax(); 118 cpu_relax();
135} 119}
136 120
137/* 121static int omap_wdt_start(struct watchdog_device *wdog)
138 * Allow only one task to hold it open
139 */
140static int omap_wdt_open(struct inode *inode, struct file *file)
141{ 122{
142 struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev); 123 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
143 void __iomem *base = wdev->base; 124 void __iomem *base = wdev->base;
144 125
145 if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users))) 126 mutex_lock(&wdev->lock);
146 return -EBUSY; 127
128 wdev->omap_wdt_users = true;
147 129
148 pm_runtime_get_sync(wdev->dev); 130 pm_runtime_get_sync(wdev->dev);
149 131
@@ -155,117 +137,81 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
155 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) 137 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
156 cpu_relax(); 138 cpu_relax();
157 139
158 file->private_data = (void *) wdev; 140 omap_wdt_set_timer(wdev, wdog->timeout);
159 141 omap_wdt_reload(wdev); /* trigger loading of new timeout value */
160 omap_wdt_set_timeout(wdev);
161 omap_wdt_ping(wdev); /* trigger loading of new timeout value */
162 omap_wdt_enable(wdev); 142 omap_wdt_enable(wdev);
163 143
164 return nonseekable_open(inode, file); 144 mutex_unlock(&wdev->lock);
145
146 return 0;
165} 147}
166 148
167static int omap_wdt_release(struct inode *inode, struct file *file) 149static int omap_wdt_stop(struct watchdog_device *wdog)
168{ 150{
169 struct omap_wdt_dev *wdev = file->private_data; 151 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
170 152
171 /* 153 mutex_lock(&wdev->lock);
172 * Shut off the timer unless NOWAYOUT is defined.
173 */
174#ifndef CONFIG_WATCHDOG_NOWAYOUT
175 omap_wdt_disable(wdev); 154 omap_wdt_disable(wdev);
176
177 pm_runtime_put_sync(wdev->dev); 155 pm_runtime_put_sync(wdev->dev);
178#else 156 wdev->omap_wdt_users = false;
179 pr_crit("Unexpected close, not stopping!\n"); 157 mutex_unlock(&wdev->lock);
180#endif
181 wdev->omap_wdt_users = 0;
182
183 return 0; 158 return 0;
184} 159}
185 160
186static ssize_t omap_wdt_write(struct file *file, const char __user *data, 161static int omap_wdt_ping(struct watchdog_device *wdog)
187 size_t len, loff_t *ppos)
188{ 162{
189 struct omap_wdt_dev *wdev = file->private_data; 163 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
190 164
191 /* Refresh LOAD_TIME. */ 165 mutex_lock(&wdev->lock);
192 if (len) { 166 omap_wdt_reload(wdev);
193 spin_lock(&wdt_lock); 167 mutex_unlock(&wdev->lock);
194 omap_wdt_ping(wdev); 168
195 spin_unlock(&wdt_lock); 169 return 0;
196 }
197 return len;
198} 170}
199 171
200static long omap_wdt_ioctl(struct file *file, unsigned int cmd, 172static int omap_wdt_set_timeout(struct watchdog_device *wdog,
201 unsigned long arg) 173 unsigned int timeout)
202{ 174{
203 struct omap_wd_timer_platform_data *pdata; 175 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
204 struct omap_wdt_dev *wdev;
205 u32 rs;
206 int new_margin, bs;
207 static const struct watchdog_info ident = {
208 .identity = "OMAP Watchdog",
209 .options = WDIOF_SETTIMEOUT,
210 .firmware_version = 0,
211 };
212
213 wdev = file->private_data;
214 pdata = wdev->dev->platform_data;
215
216 switch (cmd) {
217 case WDIOC_GETSUPPORT:
218 return copy_to_user((struct watchdog_info __user *)arg, &ident,
219 sizeof(ident));
220 case WDIOC_GETSTATUS:
221 return put_user(0, (int __user *)arg);
222 case WDIOC_GETBOOTSTATUS:
223 if (!pdata || !pdata->read_reset_sources)
224 return put_user(0, (int __user *)arg);
225 rs = pdata->read_reset_sources();
226 bs = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
227 WDIOF_CARDRESET : 0;
228 return put_user(bs, (int __user *)arg);
229 case WDIOC_KEEPALIVE:
230 spin_lock(&wdt_lock);
231 omap_wdt_ping(wdev);
232 spin_unlock(&wdt_lock);
233 return 0;
234 case WDIOC_SETTIMEOUT:
235 if (get_user(new_margin, (int __user *)arg))
236 return -EFAULT;
237 omap_wdt_adjust_timeout(new_margin);
238
239 spin_lock(&wdt_lock);
240 omap_wdt_disable(wdev);
241 omap_wdt_set_timeout(wdev);
242 omap_wdt_enable(wdev);
243 176
244 omap_wdt_ping(wdev); 177 mutex_lock(&wdev->lock);
245 spin_unlock(&wdt_lock); 178 omap_wdt_disable(wdev);
246 /* Fall */ 179 omap_wdt_set_timer(wdev, timeout);
247 case WDIOC_GETTIMEOUT: 180 omap_wdt_enable(wdev);
248 return put_user(timer_margin, (int __user *)arg); 181 omap_wdt_reload(wdev);
249 default: 182 wdog->timeout = timeout;
250 return -ENOTTY; 183 mutex_unlock(&wdev->lock);
251 } 184
185 return 0;
252} 186}
253 187
254static const struct file_operations omap_wdt_fops = { 188static const struct watchdog_info omap_wdt_info = {
255 .owner = THIS_MODULE, 189 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
256 .write = omap_wdt_write, 190 .identity = "OMAP Watchdog",
257 .unlocked_ioctl = omap_wdt_ioctl, 191};
258 .open = omap_wdt_open, 192
259 .release = omap_wdt_release, 193static const struct watchdog_ops omap_wdt_ops = {
260 .llseek = no_llseek, 194 .owner = THIS_MODULE,
195 .start = omap_wdt_start,
196 .stop = omap_wdt_stop,
197 .ping = omap_wdt_ping,
198 .set_timeout = omap_wdt_set_timeout,
261}; 199};
262 200
263static int omap_wdt_probe(struct platform_device *pdev) 201static int omap_wdt_probe(struct platform_device *pdev)
264{ 202{
203 struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data;
204 bool nowayout = WATCHDOG_NOWAYOUT;
205 struct watchdog_device *omap_wdt;
265 struct resource *res, *mem; 206 struct resource *res, *mem;
266 struct omap_wdt_dev *wdev; 207 struct omap_wdt_dev *wdev;
208 u32 rs;
267 int ret; 209 int ret;
268 210
211 omap_wdt = kzalloc(sizeof(*omap_wdt), GFP_KERNEL);
212 if (!omap_wdt)
213 return -ENOMEM;
214
269 /* reserve static register mappings */ 215 /* reserve static register mappings */
270 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 216 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
271 if (!res) { 217 if (!res) {
@@ -273,11 +219,6 @@ static int omap_wdt_probe(struct platform_device *pdev)
273 goto err_get_resource; 219 goto err_get_resource;
274 } 220 }
275 221
276 if (omap_wdt_dev) {
277 ret = -EBUSY;
278 goto err_busy;
279 }
280
281 mem = request_mem_region(res->start, resource_size(res), pdev->name); 222 mem = request_mem_region(res->start, resource_size(res), pdev->name);
282 if (!mem) { 223 if (!mem) {
283 ret = -EBUSY; 224 ret = -EBUSY;
@@ -290,9 +231,11 @@ static int omap_wdt_probe(struct platform_device *pdev)
290 goto err_kzalloc; 231 goto err_kzalloc;
291 } 232 }
292 233
293 wdev->omap_wdt_users = 0; 234 wdev->omap_wdt_users = false;
294 wdev->mem = mem; 235 wdev->mem = mem;
295 wdev->dev = &pdev->dev; 236 wdev->dev = &pdev->dev;
237 wdev->wdt_trgr_pattern = 0x1234;
238 mutex_init(&wdev->lock);
296 239
297 wdev->base = ioremap(res->start, resource_size(res)); 240 wdev->base = ioremap(res->start, resource_size(res));
298 if (!wdev->base) { 241 if (!wdev->base) {
@@ -300,34 +243,47 @@ static int omap_wdt_probe(struct platform_device *pdev)
300 goto err_ioremap; 243 goto err_ioremap;
301 } 244 }
302 245
303 platform_set_drvdata(pdev, wdev); 246 omap_wdt->info = &omap_wdt_info;
247 omap_wdt->ops = &omap_wdt_ops;
248 omap_wdt->min_timeout = TIMER_MARGIN_MIN;
249 omap_wdt->max_timeout = TIMER_MARGIN_MAX;
250
251 if (timer_margin >= TIMER_MARGIN_MIN &&
252 timer_margin <= TIMER_MARGIN_MAX)
253 omap_wdt->timeout = timer_margin;
254 else
255 omap_wdt->timeout = TIMER_MARGIN_DEFAULT;
256
257 watchdog_set_drvdata(omap_wdt, wdev);
258 watchdog_set_nowayout(omap_wdt, nowayout);
259
260 platform_set_drvdata(pdev, omap_wdt);
304 261
305 pm_runtime_enable(wdev->dev); 262 pm_runtime_enable(wdev->dev);
306 pm_runtime_get_sync(wdev->dev); 263 pm_runtime_get_sync(wdev->dev);
307 264
308 omap_wdt_disable(wdev); 265 if (pdata && pdata->read_reset_sources)
309 omap_wdt_adjust_timeout(timer_margin); 266 rs = pdata->read_reset_sources();
267 else
268 rs = 0;
269 omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
270 WDIOF_CARDRESET : 0;
310 271
311 wdev->omap_wdt_miscdev.parent = &pdev->dev; 272 omap_wdt_disable(wdev);
312 wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
313 wdev->omap_wdt_miscdev.name = "watchdog";
314 wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
315 273
316 ret = misc_register(&(wdev->omap_wdt_miscdev)); 274 ret = watchdog_register_device(omap_wdt);
317 if (ret) 275 if (ret)
318 goto err_misc; 276 goto err_register;
319 277
320 pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", 278 pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
321 __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, 279 __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
322 timer_margin); 280 omap_wdt->timeout);
323 281
324 pm_runtime_put_sync(wdev->dev); 282 pm_runtime_put_sync(wdev->dev);
325 283
326 omap_wdt_dev = pdev;
327
328 return 0; 284 return 0;
329 285
330err_misc: 286err_register:
331 pm_runtime_disable(wdev->dev); 287 pm_runtime_disable(wdev->dev);
332 platform_set_drvdata(pdev, NULL); 288 platform_set_drvdata(pdev, NULL);
333 iounmap(wdev->base); 289 iounmap(wdev->base);
@@ -341,37 +297,38 @@ err_kzalloc:
341 297
342err_busy: 298err_busy:
343err_get_resource: 299err_get_resource:
344 300 kfree(omap_wdt);
345 return ret; 301 return ret;
346} 302}
347 303
348static void omap_wdt_shutdown(struct platform_device *pdev) 304static void omap_wdt_shutdown(struct platform_device *pdev)
349{ 305{
350 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 306 struct watchdog_device *wdog = platform_get_drvdata(pdev);
307 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
351 308
309 mutex_lock(&wdev->lock);
352 if (wdev->omap_wdt_users) { 310 if (wdev->omap_wdt_users) {
353 omap_wdt_disable(wdev); 311 omap_wdt_disable(wdev);
354 pm_runtime_put_sync(wdev->dev); 312 pm_runtime_put_sync(wdev->dev);
355 } 313 }
314 mutex_unlock(&wdev->lock);
356} 315}
357 316
358static int omap_wdt_remove(struct platform_device *pdev) 317static int omap_wdt_remove(struct platform_device *pdev)
359{ 318{
360 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 319 struct watchdog_device *wdog = platform_get_drvdata(pdev);
320 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
361 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 321 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
362 322
363 pm_runtime_disable(wdev->dev); 323 pm_runtime_disable(wdev->dev);
364 if (!res) 324 watchdog_unregister_device(wdog);
365 return -ENOENT;
366
367 misc_deregister(&(wdev->omap_wdt_miscdev));
368 release_mem_region(res->start, resource_size(res)); 325 release_mem_region(res->start, resource_size(res));
369 platform_set_drvdata(pdev, NULL); 326 platform_set_drvdata(pdev, NULL);
370 327
371 iounmap(wdev->base); 328 iounmap(wdev->base);
372 329
373 kfree(wdev); 330 kfree(wdev);
374 omap_wdt_dev = NULL; 331 kfree(wdog);
375 332
376 return 0; 333 return 0;
377} 334}
@@ -386,25 +343,31 @@ static int omap_wdt_remove(struct platform_device *pdev)
386 343
387static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) 344static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
388{ 345{
389 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 346 struct watchdog_device *wdog = platform_get_drvdata(pdev);
347 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
390 348
349 mutex_lock(&wdev->lock);
391 if (wdev->omap_wdt_users) { 350 if (wdev->omap_wdt_users) {
392 omap_wdt_disable(wdev); 351 omap_wdt_disable(wdev);
393 pm_runtime_put_sync(wdev->dev); 352 pm_runtime_put_sync(wdev->dev);
394 } 353 }
354 mutex_unlock(&wdev->lock);
395 355
396 return 0; 356 return 0;
397} 357}
398 358
399static int omap_wdt_resume(struct platform_device *pdev) 359static int omap_wdt_resume(struct platform_device *pdev)
400{ 360{
401 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 361 struct watchdog_device *wdog = platform_get_drvdata(pdev);
362 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
402 363
364 mutex_lock(&wdev->lock);
403 if (wdev->omap_wdt_users) { 365 if (wdev->omap_wdt_users) {
404 pm_runtime_get_sync(wdev->dev); 366 pm_runtime_get_sync(wdev->dev);
405 omap_wdt_enable(wdev); 367 omap_wdt_enable(wdev);
406 omap_wdt_ping(wdev); 368 omap_wdt_reload(wdev);
407 } 369 }
370 mutex_unlock(&wdev->lock);
408 371
409 return 0; 372 return 0;
410} 373}
@@ -437,5 +400,4 @@ module_platform_driver(omap_wdt_driver);
437 400
438MODULE_AUTHOR("George G. Davis"); 401MODULE_AUTHOR("George G. Davis");
439MODULE_LICENSE("GPL"); 402MODULE_LICENSE("GPL");
440MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
441MODULE_ALIAS("platform:omap_wdt"); 403MODULE_ALIAS("platform:omap_wdt");