26 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28 #include <linux/module.h>
30 #include <linux/types.h>
33 #include <linux/watchdog.h>
41 #include <linux/slab.h>
47 #undef S3C_VA_WATCHDOG
48 #define S3C_VA_WATCHDOG (0)
52 #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
53 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
58 static int soft_noboot;
70 "Watchdog is started at boot time if set to 1, default="
72 MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
74 MODULE_PARM_DESC(soft_noboot,
"Watchdog action, set to 1 to ignore reboots, "
75 "0 to reboot (default 0)");
78 static struct device *wdt_dev;
81 static struct clk *wdt_clock;
83 static unsigned int wdt_count;
88 #define DBG(fmt, ...) \
91 pr_info(fmt, ##__VA_ARGS__); \
100 spin_unlock(&wdt_lock);
105 static void __s3c2410wdt_stop(
void)
116 spin_lock(&wdt_lock);
118 spin_unlock(&wdt_lock);
127 spin_lock(&wdt_lock);
142 DBG(
"%s: wdt_count=0x%08x, wtcon=%08lx\n",
143 __func__, wdt_count, wtcon);
148 spin_unlock(&wdt_lock);
153 static inline int s3c2410wdt_is_running(
void)
158 static int s3c2410wdt_set_heartbeat(
struct watchdog_device *wdd,
unsigned timeout)
169 count = timeout *
freq;
171 DBG(
"%s: count=%d, timeout=%d, freq=%lu\n",
172 __func__, count, timeout, freq);
179 if (count >= 0x10000) {
180 for (divisor = 1; divisor <= 0x100; divisor++) {
181 if ((count / divisor) < 0x10000)
185 if ((count / divisor) >= 0x10000) {
186 dev_err(wdt_dev,
"timeout %d too big\n", timeout);
191 DBG(
"%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
192 __func__, timeout, divisor, count, count/divisor);
210 #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
214 .firmware_version = 0,
215 .identity =
"S3C2410 Watchdog",
220 .start = s3c2410wdt_start,
221 .stop = s3c2410wdt_stop,
222 .ping = s3c2410wdt_keepalive,
223 .set_timeout = s3c2410wdt_set_heartbeat,
227 .info = &s3c2410_wdt_ident,
228 .ops = &s3c2410wdt_ops,
235 dev_info(wdt_dev,
"watchdog timer expired (irq)\n");
237 s3c2410wdt_keepalive(&s3c2410_wdd);
242 #ifdef CONFIG_CPU_FREQ
244 static int s3c2410wdt_cpufreq_transition(
struct notifier_block *nb,
249 if (!s3c2410wdt_is_running())
258 s3c2410wdt_keepalive(&s3c2410_wdd);
260 s3c2410wdt_stop(&s3c2410_wdd);
262 ret = s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.
timeout);
265 s3c2410wdt_start(&s3c2410_wdd);
274 dev_err(wdt_dev,
"cannot set new value for timeout %d\n",
283 static inline int s3c2410wdt_cpufreq_register(
void)
289 static inline void s3c2410wdt_cpufreq_deregister(
void)
296 static inline int s3c2410wdt_cpufreq_register(
void)
301 static inline void s3c2410wdt_cpufreq_deregister(
void)
314 DBG(
"%s: probe=%p\n", __func__, pdev);
317 wdt_dev = &pdev->
dev;
320 if (wdt_mem ==
NULL) {
321 dev_err(dev,
"no memory resource specified\n");
326 if (wdt_irq ==
NULL) {
327 dev_err(dev,
"no irq resource specified\n");
334 size = resource_size(wdt_mem);
336 dev_err(dev,
"failed to get memory region\n");
342 if (wdt_base ==
NULL) {
343 dev_err(dev,
"failed to ioremap() region\n");
348 DBG(
"probe: mapped wdt_base=%p\n", wdt_base);
351 if (IS_ERR(wdt_clock)) {
352 dev_err(dev,
"failed to find watchdog clock source\n");
353 ret = PTR_ERR(wdt_clock);
359 ret = s3c2410wdt_cpufreq_register();
361 pr_err(
"failed to register cpufreq\n");
368 if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, tmr_margin)) {
369 started = s3c2410wdt_set_heartbeat(&s3c2410_wdd,
374 "tmr_margin value out of range, default %d used\n",
377 dev_info(dev,
"default timer value is out of range, "
383 dev_err(dev,
"failed to install irq (%d)\n", ret);
387 watchdog_set_nowayout(&s3c2410_wdd, nowayout);
391 dev_err(dev,
"cannot register watchdog (%d)\n", ret);
395 if (tmr_atboot && started == 0) {
396 dev_info(dev,
"starting watchdog timer\n");
397 s3c2410wdt_start(&s3c2410_wdd);
398 }
else if (!tmr_atboot) {
403 s3c2410wdt_stop(&s3c2410_wdd);
410 dev_info(dev,
"watchdog %sactive, reset %sabled, irq %sabled\n",
421 s3c2410wdt_cpufreq_deregister();
446 s3c2410wdt_cpufreq_deregister();
462 s3c2410wdt_stop(&s3c2410_wdd);
467 static unsigned long wtcon_save;
468 static unsigned long wtdat_save;
477 s3c2410wdt_stop(&s3c2410_wdd);
491 (wtcon_save & S3C2410_WTCON_ENABLE) ?
"en" :
"dis");
497 #define s3c2410wdt_suspend NULL
498 #define s3c2410wdt_resume NULL
502 static const struct of_device_id s3c2410_wdt_match[] = {
510 .probe = s3c2410wdt_probe,
512 .shutdown = s3c2410wdt_shutdown,
517 .name =
"s3c2410-wdt",