aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorBen Dooks <ben@simtec.co.uk>2009-10-29 20:30:25 -0400
committerWim Van Sebroeck <wim@iguana.be>2009-12-04 08:20:28 -0500
commite02f838eedef1533f7a1bcf21fe724c3c93093f9 (patch)
treed1c032ac403a6ebf90fbc8e3294030b3eb83ab2d /drivers/watchdog
parent22763c5cf3690a681551162c15d34d935308c8d7 (diff)
[WATCHDOG] CPUFREQ: S3C24XX Watchdog frequency scaling support.
Add support for CPU frequency scaling to the S3C24XX Watchdog driver. Signed-off-by: Simtec Linux Team <linux@simtec.co.uk> Signed-off-by: Ben Dooks <ben@simtec.co.uk> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/s3c2410_wdt.c89
1 files changed, 86 insertions, 3 deletions
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index b57ac6b49147..85b93e15d011 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -36,6 +36,7 @@
36#include <linux/clk.h> 36#include <linux/clk.h>
37#include <linux/uaccess.h> 37#include <linux/uaccess.h>
38#include <linux/io.h> 38#include <linux/io.h>
39#include <linux/cpufreq.h>
39 40
40#include <mach/map.h> 41#include <mach/map.h>
41 42
@@ -142,9 +143,14 @@ static void s3c2410wdt_start(void)
142 spin_unlock(&wdt_lock); 143 spin_unlock(&wdt_lock);
143} 144}
144 145
146static inline int s3c2410wdt_is_running(void)
147{
148 return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
149}
150
145static int s3c2410wdt_set_heartbeat(int timeout) 151static int s3c2410wdt_set_heartbeat(int timeout)
146{ 152{
147 unsigned int freq = clk_get_rate(wdt_clock); 153 unsigned long freq = clk_get_rate(wdt_clock);
148 unsigned int count; 154 unsigned int count;
149 unsigned int divisor = 1; 155 unsigned int divisor = 1;
150 unsigned long wtcon; 156 unsigned long wtcon;
@@ -155,7 +161,7 @@ static int s3c2410wdt_set_heartbeat(int timeout)
155 freq /= 128; 161 freq /= 128;
156 count = timeout * freq; 162 count = timeout * freq;
157 163
158 DBG("%s: count=%d, timeout=%d, freq=%d\n", 164 DBG("%s: count=%d, timeout=%d, freq=%lu\n",
159 __func__, count, timeout, freq); 165 __func__, count, timeout, freq);
160 166
161 /* if the count is bigger than the watchdog register, 167 /* if the count is bigger than the watchdog register,
@@ -324,6 +330,73 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
324 s3c2410wdt_keepalive(); 330 s3c2410wdt_keepalive();
325 return IRQ_HANDLED; 331 return IRQ_HANDLED;
326} 332}
333
334
335#ifdef CONFIG_CPU_FREQ
336
337static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
338 unsigned long val, void *data)
339{
340 int ret;
341
342 if (!s3c2410wdt_is_running())
343 goto done;
344
345 if (val == CPUFREQ_PRECHANGE) {
346 /* To ensure that over the change we don't cause the
347 * watchdog to trigger, we perform an keep-alive if
348 * the watchdog is running.
349 */
350
351 s3c2410wdt_keepalive();
352 } else if (val == CPUFREQ_POSTCHANGE) {
353 s3c2410wdt_stop();
354
355 ret = s3c2410wdt_set_heartbeat(tmr_margin);
356
357 if (ret >= 0)
358 s3c2410wdt_start();
359 else
360 goto err;
361 }
362
363done:
364 return 0;
365
366 err:
367 dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin);
368 return ret;
369}
370
371static struct notifier_block s3c2410wdt_cpufreq_transition_nb = {
372 .notifier_call = s3c2410wdt_cpufreq_transition,
373};
374
375static inline int s3c2410wdt_cpufreq_register(void)
376{
377 return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb,
378 CPUFREQ_TRANSITION_NOTIFIER);
379}
380
381static inline void s3c2410wdt_cpufreq_deregister(void)
382{
383 cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb,
384 CPUFREQ_TRANSITION_NOTIFIER);
385}
386
387#else
388static inline int s3c2410wdt_cpufreq_register(void)
389{
390 return 0;
391}
392
393static inline void s3c2410wdt_cpufreq_deregister(void)
394{
395}
396#endif
397
398
399
327/* device interface */ 400/* device interface */
328 401
329static int __devinit s3c2410wdt_probe(struct platform_device *pdev) 402static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
@@ -387,6 +460,11 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
387 460
388 clk_enable(wdt_clock); 461 clk_enable(wdt_clock);
389 462
463 if (s3c2410wdt_cpufreq_register() < 0) {
464 printk(KERN_ERR PFX "failed to register cpufreq\n");
465 goto err_clk;
466 }
467
390 /* see if we can actually set the requested timer margin, and if 468 /* see if we can actually set the requested timer margin, and if
391 * not, try the default value */ 469 * not, try the default value */
392 470
@@ -407,7 +485,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
407 if (ret) { 485 if (ret) {
408 dev_err(dev, "cannot register miscdev on minor=%d (%d)\n", 486 dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
409 WATCHDOG_MINOR, ret); 487 WATCHDOG_MINOR, ret);
410 goto err_clk; 488 goto err_cpufreq;
411 } 489 }
412 490
413 if (tmr_atboot && started == 0) { 491 if (tmr_atboot && started == 0) {
@@ -432,6 +510,9 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
432 510
433 return 0; 511 return 0;
434 512
513 err_cpufreq:
514 s3c2410wdt_cpufreq_deregister();
515
435 err_clk: 516 err_clk:
436 clk_disable(wdt_clock); 517 clk_disable(wdt_clock);
437 clk_put(wdt_clock); 518 clk_put(wdt_clock);
@@ -451,6 +532,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
451 532
452static int __devexit s3c2410wdt_remove(struct platform_device *dev) 533static int __devexit s3c2410wdt_remove(struct platform_device *dev)
453{ 534{
535 s3c2410wdt_cpufreq_deregister();
536
454 release_resource(wdt_mem); 537 release_resource(wdt_mem);
455 kfree(wdt_mem); 538 kfree(wdt_mem);
456 wdt_mem = NULL; 539 wdt_mem = NULL;