Commit 67c0f55468443ef8a1edc6ee92f9a92e4915be24

Authored by Aaro Koskinen
Committed by Wim Van Sebroeck
1 parent cf13a84d17

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>

Showing 2 changed files with 112 additions and 149 deletions Side-by-side Diff

drivers/watchdog/Kconfig
... ... @@ -232,6 +232,7 @@
232 232 config OMAP_WATCHDOG
233 233 tristate "OMAP Watchdog"
234 234 depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
  235 + select WATCHDOG_CORE
235 236 help
236 237 Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y'
237 238 here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
drivers/watchdog/omap_wdt.c
... ... @@ -31,42 +31,34 @@
31 31 #include <linux/module.h>
32 32 #include <linux/types.h>
33 33 #include <linux/kernel.h>
34   -#include <linux/fs.h>
35 34 #include <linux/mm.h>
36   -#include <linux/miscdevice.h>
37 35 #include <linux/watchdog.h>
38 36 #include <linux/reboot.h>
39 37 #include <linux/init.h>
40 38 #include <linux/err.h>
41 39 #include <linux/platform_device.h>
42 40 #include <linux/moduleparam.h>
43   -#include <linux/bitops.h>
44 41 #include <linux/io.h>
45   -#include <linux/uaccess.h>
46 42 #include <linux/slab.h>
47 43 #include <linux/pm_runtime.h>
48 44 #include <linux/platform_data/omap-wd-timer.h>
49 45  
50 46 #include "omap_wdt.h"
51 47  
52   -static struct platform_device *omap_wdt_dev;
53   -
54 48 static unsigned timer_margin;
55 49 module_param(timer_margin, uint, 0);
56 50 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
57 51  
58   -static unsigned int wdt_trgr_pattern = 0x1234;
59   -static DEFINE_SPINLOCK(wdt_lock);
60   -
61 52 struct omap_wdt_dev {
62 53 void __iomem *base; /* physical */
63 54 struct device *dev;
64   - int omap_wdt_users;
  55 + bool omap_wdt_users;
65 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  
69   -static void omap_wdt_ping(struct omap_wdt_dev *wdev)
  61 +static void omap_wdt_reload(struct omap_wdt_dev *wdev)
70 62 {
71 63 void __iomem *base = wdev->base;
72 64  
... ... @@ -74,8 +66,8 @@
74 66 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
75 67 cpu_relax();
76 68  
77   - wdt_trgr_pattern = ~wdt_trgr_pattern;
78   - __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
  69 + wdev->wdt_trgr_pattern = ~wdev->wdt_trgr_pattern;
  70 + __raw_writel(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
79 71  
80 72 /* wait for posted write to complete */
81 73 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
82 74  
... ... @@ -111,18 +103,10 @@
111 103 cpu_relax();
112 104 }
113 105  
114   -static void omap_wdt_adjust_timeout(unsigned new_timeout)
  106 +static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
  107 + unsigned int timeout)
115 108 {
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   -
123   -static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
124   -{
125   - u32 pre_margin = GET_WLDR_VAL(timer_margin);
  109 + u32 pre_margin = GET_WLDR_VAL(timeout);
126 110 void __iomem *base = wdev->base;
127 111  
128 112 /* just count up at 32 KHz */
129 113  
130 114  
131 115  
... ... @@ -134,17 +118,15 @@
134 118 cpu_relax();
135 119 }
136 120  
137   -/*
138   - * Allow only one task to hold it open
139   - */
140   -static int omap_wdt_open(struct inode *inode, struct file *file)
  121 +static int omap_wdt_start(struct watchdog_device *wdog)
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 124 void __iomem *base = wdev->base;
144 125  
145   - if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
146   - return -EBUSY;
  126 + mutex_lock(&wdev->lock);
147 127  
  128 + wdev->omap_wdt_users = true;
  129 +
148 130 pm_runtime_get_sync(wdev->dev);
149 131  
150 132 /* initialize prescaler */
151 133  
152 134  
153 135  
154 136  
155 137  
156 138  
157 139  
158 140  
159 141  
160 142  
161 143  
162 144  
163 145  
164 146  
165 147  
166 148  
167 149  
168 150  
... ... @@ -155,117 +137,81 @@
155 137 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
156 138 cpu_relax();
157 139  
158   - file->private_data = (void *) wdev;
159   -
160   - omap_wdt_set_timeout(wdev);
161   - omap_wdt_ping(wdev); /* trigger loading of new timeout value */
  140 + omap_wdt_set_timer(wdev, wdog->timeout);
  141 + omap_wdt_reload(wdev); /* trigger loading of new timeout value */
162 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  
167   -static int omap_wdt_release(struct inode *inode, struct file *file)
  149 +static 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   - /*
172   - * Shut off the timer unless NOWAYOUT is defined.
173   - */
174   -#ifndef CONFIG_WATCHDOG_NOWAYOUT
  153 + mutex_lock(&wdev->lock);
175 154 omap_wdt_disable(wdev);
176   -
177 155 pm_runtime_put_sync(wdev->dev);
178   -#else
179   - pr_crit("Unexpected close, not stopping!\n");
180   -#endif
181   - wdev->omap_wdt_users = 0;
182   -
  156 + wdev->omap_wdt_users = false;
  157 + mutex_unlock(&wdev->lock);
183 158 return 0;
184 159 }
185 160  
186   -static ssize_t omap_wdt_write(struct file *file, const char __user *data,
187   - size_t len, loff_t *ppos)
  161 +static int omap_wdt_ping(struct watchdog_device *wdog)
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. */
192   - if (len) {
193   - spin_lock(&wdt_lock);
194   - omap_wdt_ping(wdev);
195   - spin_unlock(&wdt_lock);
196   - }
197   - return len;
  165 + mutex_lock(&wdev->lock);
  166 + omap_wdt_reload(wdev);
  167 + mutex_unlock(&wdev->lock);
  168 +
  169 + return 0;
198 170 }
199 171  
200   -static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
201   - unsigned long arg)
  172 +static int omap_wdt_set_timeout(struct watchdog_device *wdog,
  173 + unsigned int timeout)
202 174 {
203   - struct omap_wd_timer_platform_data *pdata;
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   - };
  175 + struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
212 176  
213   - wdev = file->private_data;
214   - pdata = wdev->dev->platform_data;
  177 + mutex_lock(&wdev->lock);
  178 + omap_wdt_disable(wdev);
  179 + omap_wdt_set_timer(wdev, timeout);
  180 + omap_wdt_enable(wdev);
  181 + omap_wdt_reload(wdev);
  182 + wdog->timeout = timeout;
  183 + mutex_unlock(&wdev->lock);
215 184  
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   -
244   - omap_wdt_ping(wdev);
245   - spin_unlock(&wdt_lock);
246   - /* Fall */
247   - case WDIOC_GETTIMEOUT:
248   - return put_user(timer_margin, (int __user *)arg);
249   - default:
250   - return -ENOTTY;
251   - }
  185 + return 0;
252 186 }
253 187  
254   -static const struct file_operations omap_wdt_fops = {
255   - .owner = THIS_MODULE,
256   - .write = omap_wdt_write,
257   - .unlocked_ioctl = omap_wdt_ioctl,
258   - .open = omap_wdt_open,
259   - .release = omap_wdt_release,
260   - .llseek = no_llseek,
  188 +static const struct watchdog_info omap_wdt_info = {
  189 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
  190 + .identity = "OMAP Watchdog",
261 191 };
262 192  
  193 +static const struct watchdog_ops omap_wdt_ops = {
  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,
  199 +};
  200 +
263 201 static 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 206 struct resource *res, *mem;
266 207 struct omap_wdt_dev *wdev;
  208 + u32 rs;
267 209 int ret;
268 210  
  211 + omap_wdt = kzalloc(sizeof(*omap_wdt), GFP_KERNEL);
  212 + if (!omap_wdt)
  213 + return -ENOMEM;
  214 +
269 215 /* reserve static register mappings */
270 216 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
271 217 if (!res) {
... ... @@ -273,11 +219,6 @@
273 219 goto err_get_resource;
274 220 }
275 221  
276   - if (omap_wdt_dev) {
277   - ret = -EBUSY;
278   - goto err_busy;
279   - }
280   -
281 222 mem = request_mem_region(res->start, resource_size(res), pdev->name);
282 223 if (!mem) {
283 224 ret = -EBUSY;
... ... @@ -290,9 +231,11 @@
290 231 goto err_kzalloc;
291 232 }
292 233  
293   - wdev->omap_wdt_users = 0;
294   - wdev->mem = mem;
295   - wdev->dev = &pdev->dev;
  234 + wdev->omap_wdt_users = false;
  235 + wdev->mem = mem;
  236 + wdev->dev = &pdev->dev;
  237 + wdev->wdt_trgr_pattern = 0x1234;
  238 + mutex_init(&wdev->lock);
296 239  
297 240 wdev->base = ioremap(res->start, resource_size(res));
298 241 if (!wdev->base) {
299 242  
300 243  
301 244  
302 245  
303 246  
304 247  
305 248  
306 249  
... ... @@ -300,34 +243,47 @@
300 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;
304 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);
  261 +
305 262 pm_runtime_enable(wdev->dev);
306 263 pm_runtime_get_sync(wdev->dev);
307 264  
  265 + if (pdata && pdata->read_reset_sources)
  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;
  271 +
308 272 omap_wdt_disable(wdev);
309   - omap_wdt_adjust_timeout(timer_margin);
310 273  
311   - wdev->omap_wdt_miscdev.parent = &pdev->dev;
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   -
316   - ret = misc_register(&(wdev->omap_wdt_miscdev));
  274 + ret = watchdog_register_device(omap_wdt);
317 275 if (ret)
318   - goto err_misc;
  276 + goto err_register;
319 277  
320 278 pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
321 279 __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
322   - timer_margin);
  280 + omap_wdt->timeout);
323 281  
324 282 pm_runtime_put_sync(wdev->dev);
325 283  
326   - omap_wdt_dev = pdev;
327   -
328 284 return 0;
329 285  
330   -err_misc:
  286 +err_register:
331 287 pm_runtime_disable(wdev->dev);
332 288 platform_set_drvdata(pdev, NULL);
333 289 iounmap(wdev->base);
334 290  
335 291  
336 292  
337 293  
338 294  
339 295  
... ... @@ -341,37 +297,38 @@
341 297  
342 298 err_busy:
343 299 err_get_resource:
344   -
  300 + kfree(omap_wdt);
345 301 return ret;
346 302 }
347 303  
348 304 static 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 310 if (wdev->omap_wdt_users) {
353 311 omap_wdt_disable(wdev);
354 312 pm_runtime_put_sync(wdev->dev);
355 313 }
  314 + mutex_unlock(&wdev->lock);
356 315 }
357 316  
358 317 static 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 321 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
362 322  
363 323 pm_runtime_disable(wdev->dev);
364   - if (!res)
365   - return -ENOENT;
366   -
367   - misc_deregister(&(wdev->omap_wdt_miscdev));
  324 + watchdog_unregister_device(wdog);
368 325 release_mem_region(res->start, resource_size(res));
369 326 platform_set_drvdata(pdev, NULL);
370 327  
371 328 iounmap(wdev->base);
372 329  
373 330 kfree(wdev);
374   - omap_wdt_dev = NULL;
  331 + kfree(wdog);
375 332  
376 333 return 0;
377 334 }
378 335  
379 336  
380 337  
381 338  
382 339  
383 340  
... ... @@ -386,25 +343,31 @@
386 343  
387 344 static 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 350 if (wdev->omap_wdt_users) {
392 351 omap_wdt_disable(wdev);
393 352 pm_runtime_put_sync(wdev->dev);
394 353 }
  354 + mutex_unlock(&wdev->lock);
395 355  
396 356 return 0;
397 357 }
398 358  
399 359 static 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 365 if (wdev->omap_wdt_users) {
404 366 pm_runtime_get_sync(wdev->dev);
405 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 372 return 0;
410 373 }
... ... @@ -437,6 +400,5 @@
437 400  
438 401 MODULE_AUTHOR("George G. Davis");
439 402 MODULE_LICENSE("GPL");
440   -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
441 403 MODULE_ALIAS("platform:omap_wdt");