Commit fc5c13fc authored by Ben Dooks's avatar Ben Dooks Committed by Linus Torvalds

[WATCHDOG] s3c2410_wdt.c-wdog-fix3.patch

This patch fixes the following problems:
- debug is now configurable from cmdline (see previous emails)
- re-worked the open call
- moved clock enable to before we setup watchdog
  (some units on the s3c2410 don't like their registers changing
   without the clock enabled)
- fixed bug in having two timer counts, one unused
- fixed semaphore initialisation, so opens no longer blow up
parent e891285b
/* linux/drivers/char/watchdog/s3c2410_wdt.c /* linux/drivers/char/watchdog/s3c2410_wdt.c
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
* S3C2410 Watchdog Timer Support * S3C2410 Watchdog Timer Support
* *
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Changelog:
* 05-Oct-2004 BJD Added semaphore init to stop crashes on open
* Fixed tmr_count / wdt_count confusion
* Added configurable debug
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -50,34 +55,21 @@ ...@@ -50,34 +55,21 @@
#define PFX "s3c2410-wdt: " #define PFX "s3c2410-wdt: "
#ifdef CONFIG_S3C2410_WATCHDOG_DEBUG #define CONFIG_WATCHDOG_NOWAYOUT (0)
#undef pr_debug #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#define pr_debug(msg, x...) do { printk(KERN_INFO msg, x); } while(0) #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
#endif
/* configurations from makefile */
#ifndef CONFIG_WATCHDOG_NOWAYOUT
#define CONFIG_WATCHDOG_NOWAYOUT (0)
#endif
#ifndef CONFIG_S3C2410_WATCHDOG_ATBOOT
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#endif
#ifndef CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
#endif static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
static int soft_noboot = 0;
static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME; static int debug = 0;
static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
static int soft_noboot = 0;
module_param(tmr_margin, int, 0); module_param(tmr_margin, int, 0);
module_param(tmr_atboot, int, 0); module_param(tmr_atboot, int, 0);
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
module_param(soft_noboot, int, 0); module_param(soft_noboot, int, 0);
module_param(debug, int, 0);
MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")"); MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
...@@ -87,13 +79,16 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON ...@@ -87,13 +79,16 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)"); MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
typedef enum close_state { typedef enum close_state {
CLOSE_STATE_NOT, CLOSE_STATE_NOT,
CLOSE_STATE_ALLOW=0x4021 CLOSE_STATE_ALLOW=0x4021
} close_state_t; } close_state_t;
static struct semaphore open_lock; static DECLARE_MUTEX(open_lock);
static struct resource *wdt_mem; static struct resource *wdt_mem;
static struct resource *wdt_irq; static struct resource *wdt_irq;
static struct clk *wdt_clock; static struct clk *wdt_clock;
...@@ -101,10 +96,15 @@ static void __iomem *wdt_base; ...@@ -101,10 +96,15 @@ static void __iomem *wdt_base;
static unsigned int wdt_count; static unsigned int wdt_count;
static close_state_t allow_close; static close_state_t allow_close;
static unsigned int tmr_count;
/* watchdog control routines */ /* watchdog control routines */
#define DBG(msg...) do { \
if (debug) \
printk(KERN_INFO msg); \
} while(0)
/* functions */
static int s3c2410wdt_keepalive(void) static int s3c2410wdt_keepalive(void)
{ {
writel(wdt_count, wdt_base + S3C2410_WTCNT); writel(wdt_count, wdt_base + S3C2410_WTCNT);
...@@ -126,6 +126,8 @@ static int s3c2410wdt_start(void) ...@@ -126,6 +126,8 @@ static int s3c2410wdt_start(void)
{ {
unsigned long wtcon; unsigned long wtcon;
s3c2410wdt_stop();
wtcon = readl(wdt_base + S3C2410_WTCON); wtcon = readl(wdt_base + S3C2410_WTCON);
wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128; wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
...@@ -137,12 +139,11 @@ static int s3c2410wdt_start(void) ...@@ -137,12 +139,11 @@ static int s3c2410wdt_start(void)
wtcon |= S3C2410_WTCON_RSTEN; wtcon |= S3C2410_WTCON_RSTEN;
} }
clk_enable(wdt_clock); DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
__FUNCTION__, wdt_count, wtcon);
pr_debug("%s: tmr_count=0x%08x, wtcon=%08lx\n", writel(wdt_count, wdt_base + S3C2410_WTDAT);
__FUNCTION__, tmr_count, wtcon); writel(wdt_count, wdt_base + S3C2410_WTCNT);
writel(tmr_count, wdt_base + S3C2410_WTDAT);
writel(wtcon, wdt_base + S3C2410_WTCON); writel(wtcon, wdt_base + S3C2410_WTCON);
return 0; return 0;
...@@ -167,8 +168,8 @@ static int s3c2410wdt_set_heartbeat(int timeout) ...@@ -167,8 +168,8 @@ static int s3c2410wdt_set_heartbeat(int timeout)
freq /= 128/2; freq /= 128/2;
count = timeout * freq; count = timeout * freq;
pr_debug("%s: count=%d, timeout=%d, freq=%d\n", DBG("%s: count=%d, timeout=%d, freq=%d\n",
__FUNCTION__, count, timeout, freq); __FUNCTION__, count, timeout, freq);
/* if the count is bigger than the watchdog register, /* if the count is bigger than the watchdog register,
then work out what we need to do (and if) we can then work out what we need to do (and if) we can
...@@ -187,11 +188,11 @@ static int s3c2410wdt_set_heartbeat(int timeout) ...@@ -187,11 +188,11 @@ static int s3c2410wdt_set_heartbeat(int timeout)
} }
} }
pr_debug("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
__FUNCTION__, timeout, divisor, count, count/divisor); __FUNCTION__, timeout, divisor, count, count/divisor);
count /= divisor; count /= divisor;
tmr_count = count; wdt_count = count;
/* update the pre-scaler */ /* update the pre-scaler */
wtcon = readl(wdt_base + S3C2410_WTCON); wtcon = readl(wdt_base + S3C2410_WTCON);
...@@ -372,7 +373,7 @@ static int s3c2410wdt_probe(struct device *dev) ...@@ -372,7 +373,7 @@ static int s3c2410wdt_probe(struct device *dev)
int ret; int ret;
int size; int size;
pr_debug("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev); DBG("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);
/* get the memory region for the watchdog timer */ /* get the memory region for the watchdog timer */
...@@ -395,7 +396,7 @@ static int s3c2410wdt_probe(struct device *dev) ...@@ -395,7 +396,7 @@ static int s3c2410wdt_probe(struct device *dev)
return -EINVAL; return -EINVAL;
} }
pr_debug("wdt_base=%08lx\n", wdt_base); DBG("probe: mapped wdt_base=%px\n", wdt_base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) { if (res == NULL) {
...@@ -416,6 +417,7 @@ static int s3c2410wdt_probe(struct device *dev) ...@@ -416,6 +417,7 @@ static int s3c2410wdt_probe(struct device *dev)
} }
clk_use(wdt_clock); clk_use(wdt_clock);
clk_enable(wdt_clock);
/* see if we can actually set the requested timer margin, and if /* see if we can actually set the requested timer margin, and if
* not, try the default value */ * not, try the default value */
...@@ -487,7 +489,7 @@ static struct device_driver s3c2410wdt_driver = { ...@@ -487,7 +489,7 @@ static struct device_driver s3c2410wdt_driver = {
static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics"; static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
static int __init watchdog_init(void) static int __init watchdog_init(void)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment