public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* AT91SAM9/CAP9 watchdog driver
@ 2008-06-01 16:40 Andrew Victor
  2008-06-02  6:58 ` Alan Cox
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Andrew Victor @ 2008-06-01 16:40 UTC (permalink / raw)
  To: akpm, wim; +Cc: LAK, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 221 bytes --]

Driver to support the internal watchdog peripheral found on Atmel's
AT91SAM9 and AT91CAP9 processors (ARM).

Signed-off-by: Renaud Cerrato <r.cerrato@til-technologies.fr>
Signed-off-by: Andrew Victor <linux@maxim.org.za>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: sam9_watchdog.patch --]
[-- Type: text/x-patch; name=sam9_watchdog.patch, Size: 7810 bytes --]

diff -urN linux-2.6.26-rc3.orig/drivers/watchdog/Kconfig linux-2.6.26-rc3/drivers/watchdog/Kconfig
--- linux-2.6.26-rc3.orig/drivers/watchdog/Kconfig	2008-05-24 17:24:22.000000000 +0200
+++ linux-2.6.26-rc3/drivers/watchdog/Kconfig	2008-06-01 18:28:27.000000000 +0200
@@ -66,6 +66,14 @@
 	  Watchdog timer embedded into AT91RM9200 chips. This will reboot your
 	  system when the timeout is reached.
 
+config AT91SAM9_WATCHDOG
+	tristate "AT91SAM9 / AT91CAP9 watchdog"
+	depends on ARCH_AT91 && !ARCH_AT91RM9200
+	select WATCHDOG_NOWAYOUT
+	help
+	  Watchdog timer embedded into Atmel AT91SAM9 and AT91CAP9 processors.
+	  This will reboot your system when the timeout is reached.
+
 config 21285_WATCHDOG
 	tristate "DC21285 watchdog"
 	depends on FOOTBRIDGE
diff -urN linux-2.6.26-rc3.orig/drivers/watchdog/Makefile linux-2.6.26-rc3/drivers/watchdog/Makefile
--- linux-2.6.26-rc3.orig/drivers/watchdog/Makefile	2008-05-24 17:24:22.000000000 +0200
+++ linux-2.6.26-rc3/drivers/watchdog/Makefile	2008-06-01 18:04:40.000000000 +0200
@@ -26,6 +26,7 @@
 
 # ARM Architecture
 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
+obj-$(CONFIG_AT91SAM9_WATCHDOG) += at91sam9_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
diff -urN linux-2.6.26-rc3.orig/drivers/watchdog/at91sam9_wdt.c linux-2.6.26-rc3/drivers/watchdog/at91sam9_wdt.c
--- linux-2.6.26-rc3.orig/drivers/watchdog/at91sam9_wdt.c	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.26-rc3/drivers/watchdog/at91sam9_wdt.c	2008-06-01 18:26:08.000000000 +0200
@@ -0,0 +1,263 @@
+/*
+ * Watchdog driver for Atmel AT91SAM9x processors.
+ *
+ * Copyright (C) 2007 Renaud CERRATO r.cerrato@til-technologies.fr
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The Watchdog Timer Mode Register can be only written to once. If the
+ * timeout need to be set from Linux, be sure that the bootstrap or the
+ * bootloader doesn't write to this register.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+
+#include <asm/arch/at91_wdt.h>
+
+
+#define WDT_MAX_TIME		16	/* seconds */
+
+static int wdt_timeout = -1;		/* invalid */
+
+module_param(wdt_timeout, int, 0);
+MODULE_PARM_DESC(wdt_timeout, "Watchdog time in seconds. (default = disabled)");
+
+
+static unsigned long at91wdt_busy;
+
+/* ......................................................................... */
+
+/*
+ * Reload the watchdog timer.  (ie, pat the watchdog)
+ */
+static inline void at91_wdt_reload(void)
+{
+	at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+}
+
+/* ......................................................................... */
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &at91wdt_busy))
+		return -EBUSY;
+
+	return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &at91wdt_busy);
+	return 0;
+}
+
+/*
+ * Change the watchdog time interval.
+ */
+static int at91_wdt_settimeout(int new_time)
+{
+	unsigned int reg, mr;
+	/*
+	 * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
+	 *
+	 * Since WDV is a 12-bit counter, the maximum period is
+	 * 4096 / 256 = 16 seconds.
+	 */
+	if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
+		return -EINVAL;
+
+	wdt_timeout = new_time;
+
+	/* Program the Watchdog */
+	reg = AT91_WDT_WDRSTEN			/* causes watchdog reset */
+		| AT91_WDT_WDRPROC		/* causes processor reset */
+		| AT91_WDT_WDDBGHLT		/* disabled in debug mode */
+		| AT91_WDT_WDD			/* restart at any time */
+		| (((wdt_timeout * 256) - 1) & AT91_WDT_WDV);
+	at91_sys_write(AT91_WDT_MR, reg);
+
+	/* Check if watchdog could be programmed */
+	mr = at91_sys_read(AT91_WDT_MR);
+	if (mr != reg) {
+		printk(KERN_ERR "at91sam9_wdt: Watchdog already programmed.\n");
+		return -EIO;
+	}
+
+	at91_wdt_reload();
+
+	printk(KERN_INFO "AT91SAM9 Watchdog enabled (%d seconds, nowayout)\n",
+			wdt_timeout);
+	return 0;
+}
+
+static struct watchdog_info at91_wdt_info = {
+	.identity	= "at91sam9 watchdog",
+	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static long at91_wdt_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_value, err;
+
+	switch (cmd) {
+	case WDIOC_KEEPALIVE:
+		at91_wdt_reload();	/* pat the watchdog */
+		return 0;
+
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(argp, &at91_wdt_info,
+				sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_value, p))
+			return -EFAULT;
+
+		err = at91_wdt_settimeout(new_value);
+		if (err)
+			return err;
+
+		return put_user(wdt_timeout, p);
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(wdt_timeout, p);
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
+	}
+	return -ENOTTY;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data,
+		size_t len, loff_t *ppos)
+{
+	at91_wdt_reload();		/* pat the watchdog */
+	return len;
+}
+
+/* ......................................................................... */
+
+static const struct file_operations at91wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.unlocked_ioctl	= at91_wdt_ioctl,
+	.open		= at91_wdt_open,
+	.release	= at91_wdt_close,
+	.write		= at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &at91wdt_fops,
+};
+
+static int __init at91wdt_probe(struct platform_device *pdev)
+{
+	int res;
+
+	if (at91wdt_miscdev.parent)
+		return -EBUSY;
+	at91wdt_miscdev.parent = &pdev->dev;
+
+	res = misc_register(&at91wdt_miscdev);
+	if (res)
+		return res;
+
+	/* Set watchdog */
+	if (at91_wdt_settimeout(wdt_timeout) == -EINVAL) {
+		pr_info("at91sam9_wdt: timeout must be between 1 and %d.\n",
+			WDT_MAX_TIME);
+		return 0;
+	}
+
+	return 0;
+}
+
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+	int res;
+
+	res = misc_deregister(&at91wdt_miscdev);
+	if (!res)
+		at91wdt_miscdev.parent = NULL;
+
+	return res;
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+	return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+#else
+#define at91wdt_suspend	NULL
+#define at91wdt_resume	NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+	.remove		= __exit_p(at91wdt_remove),
+	.suspend	= at91wdt_suspend,
+	.resume		= at91wdt_resume,
+	.driver		= {
+		.name	= "at91_wdt",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91sam_wdt_init(void)
+{
+	return platform_driver_probe(&at91wdt_driver, at91wdt_probe);
+}
+
+static void __exit at91sam_wdt_exit(void)
+{
+	platform_driver_unregister(&at91wdt_driver);
+}
+
+module_init(at91sam_wdt_init);
+module_exit(at91sam_wdt_exit);
+
+MODULE_AUTHOR("Renaud CERRATO");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:at91_wdt");

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-01 16:40 AT91SAM9/CAP9 watchdog driver Andrew Victor
@ 2008-06-02  6:58 ` Alan Cox
  2008-06-03 21:23 ` Andrew Morton
  2008-06-07  6:39 ` David Brownell
  2 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2008-06-02  6:58 UTC (permalink / raw)
  To: Andrew Victor; +Cc: akpm, wim, LAK, Linux Kernel list


> +static long at91_wdt_ioctl(struct file *file, unsigned int cmd,
> +		unsigned long arg)
> +{
> +	void __user *argp = (void __user *)arg;
> +	int __user *p = argp;

No locking.. so you could get two set timeout calls in parallel. Probably
you need a simple mutex in at91_wdt_settimeout();


> +	res = misc_register(&at91wdt_miscdev);
> +	if (res)
> +		return res;
> +
> +	/* Set watchdog */
> +	if (at91_wdt_settimeout(wdt_timeout) == -EINVAL) {
> +		pr_info("at91sam9_wdt: timeout must be between 1 and %d.\n",
> +			WDT_MAX_TIME);
> +		return 0;

At the moment those two are safe. When the open lock_kernel
goes away it will be possible to get

			misc_register
						open
						ioctl
			wdt_settimout()

So you may want to swap those two around (and disable the timer if the
register fails ?), or lock the open against the register routine.

Otherwise looks good.

Alan

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-01 16:40 AT91SAM9/CAP9 watchdog driver Andrew Victor
  2008-06-02  6:58 ` Alan Cox
@ 2008-06-03 21:23 ` Andrew Morton
  2008-06-04  7:31   ` Andrew Victor
  2008-06-07  6:39 ` David Brownell
  2 siblings, 1 reply; 10+ messages in thread
From: Andrew Morton @ 2008-06-03 21:23 UTC (permalink / raw)
  To: Andrew Victor; +Cc: wim, linux-arm-kernel, linux-kernel

On Sun, 1 Jun 2008 18:40:46 +0200
"Andrew Victor" <avictor.za@gmail.com> wrote:

> +static int __init at91wdt_probe(struct platform_device *pdev)
> +{
> +	int res;
> +
> +	if (at91wdt_miscdev.parent)
> +		return -EBUSY;
> +	at91wdt_miscdev.parent = &pdev->dev;
> +
> +	res = misc_register(&at91wdt_miscdev);
> +	if (res)
> +		return res;
> +
> +	/* Set watchdog */
> +	if (at91_wdt_settimeout(wdt_timeout) == -EINVAL) {
> +		pr_info("at91sam9_wdt: timeout must be between 1 and %d.\n",
> +			WDT_MAX_TIME);

Would printk(KERN_ERR be more appropriate here?

> +		return 0;

That looks like the wrong return value?

> +	}
> +
> +	return 0;
> +}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-03 21:23 ` Andrew Morton
@ 2008-06-04  7:31   ` Andrew Victor
  2008-06-04 11:36     ` Alan Cox
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Victor @ 2008-06-04  7:31 UTC (permalink / raw)
  To: Andrew Morton; +Cc: wim, linux-arm-kernel, linux-kernel

hi Andrew,

>> +             return 0;
>
> That looks like the wrong return value?

Since the watchdog registers are Write-Once, if the user does not
specify a "wdt_timeout" parameter we'd still like the driver to load
even if it's not enabled.
The user can then always use ioctl(WDIOC_SETTIMEOUT:) to set the timeout later.


Regards,
  Andrew Victor

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-04  7:31   ` Andrew Victor
@ 2008-06-04 11:36     ` Alan Cox
  2008-06-04 18:36       ` Andrew Victor
  0 siblings, 1 reply; 10+ messages in thread
From: Alan Cox @ 2008-06-04 11:36 UTC (permalink / raw)
  To: Andrew Victor; +Cc: Andrew Morton, wim, linux-arm-kernel, linux-kernel

On Wed, 4 Jun 2008 09:31:50 +0200
"Andrew Victor" <avictor.za@gmail.com> wrote:

> hi Andrew,
> 
> >> +             return 0;
> >
> > That looks like the wrong return value?
> 
> Since the watchdog registers are Write-Once, if the user does not
> specify a "wdt_timeout" parameter we'd still like the driver to load
> even if it's not enabled.

Surely you can avoid doing the register writes until after you check the
validity of arguments ?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-04 18:36       ` Andrew Victor
@ 2008-06-04 18:24         ` Alan Cox
  2008-06-04 19:02           ` Andrew Victor
  0 siblings, 1 reply; 10+ messages in thread
From: Alan Cox @ 2008-06-04 18:24 UTC (permalink / raw)
  To: Andrew Victor; +Cc: Andrew Morton, wim, linux-arm-kernel, linux-kernel

> The issue above is rather that probe() should not fail if
> at91_wdt_settimeout() returns -EINVAL, since we'd like the
> driver/module to still load to allow the user to later specify a valid
> timeout via ioctl(WDIOC_SETTIMEOUT).

Every other watchdog behaves as follows

- If you specify a bogus value it doesn't load
- If you specify no value you get a valid default
- If you specify a valid value you get that

I don't believe yours should be different.

Alan

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-04 11:36     ` Alan Cox
@ 2008-06-04 18:36       ` Andrew Victor
  2008-06-04 18:24         ` Alan Cox
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Victor @ 2008-06-04 18:36 UTC (permalink / raw)
  To: Alan Cox; +Cc: Andrew Morton, wim, linux-arm-kernel, linux-kernel

hi Alan,

>> Since the watchdog registers are Write-Once, if the user does not
>> specify a "wdt_timeout" parameter we'd still like the driver to load
>> even if it's not enabled.
>
> Surely you can avoid doing the register writes until after you check the
> validity of arguments ?

The validity of the timeout value is checked in at91_wdt_settimeout().
 It returns -EINVAL if the timeout value is invalid.

The issue above is rather that probe() should not fail if
at91_wdt_settimeout() returns -EINVAL, since we'd like the
driver/module to still load to allow the user to later specify a valid
timeout via ioctl(WDIOC_SETTIMEOUT).


Regards,
  Andrew Victor

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-04 18:24         ` Alan Cox
@ 2008-06-04 19:02           ` Andrew Victor
  2008-06-04 19:18             ` Alan Cox
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Victor @ 2008-06-04 19:02 UTC (permalink / raw)
  To: Alan Cox; +Cc: Andrew Morton, wim, linux-arm-kernel, linux-kernel

hi Alan ,

> Every other watchdog behaves as follows
>
> - If you specify a bogus value it doesn't load
> - If you specify no value you get a valid default
> - If you specify a valid value you get that
>
> I don't believe yours should be different.

I don't think any other in-kernel watchdog driver has to deal with
write-once hardware.  On these processors once the watchdog register
is programmed, it cannot be disabled or re-programmed.
If the above behaviour is required, then we might aswell remove the
ioctl(WDIOC_SETTIMEOUT) interface for this driver since if the user
wants anything other than the default timeout they would need to pass
it via the kernel command-line or module parameters.


Regards,
  Andrew Victor

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-04 19:02           ` Andrew Victor
@ 2008-06-04 19:18             ` Alan Cox
  0 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2008-06-04 19:18 UTC (permalink / raw)
  To: Andrew Victor; +Cc: Andrew Morton, wim, linux-arm-kernel, linux-kernel

> > - If you specify a bogus value it doesn't load
> > - If you specify no value you get a valid default
> > - If you specify a valid value you get that
> >
> > I don't believe yours should be different.
> 
> I don't think any other in-kernel watchdog driver has to deal with
> write-once hardware.  On these processors once the watchdog register

That would not be the case.

> is programmed, it cannot be disabled or re-programmed.
> If the above behaviour is required, then we might aswell remove the
> ioctl(WDIOC_SETTIMEOUT) interface for this driver since if the user
> wants anything other than the default timeout they would need to pass
> it via the kernel command-line or module parameters.

Actually quit a few of them deal with various hardware limits by using a
software timer to maintain the hardware timer poking.

Alan

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: AT91SAM9/CAP9 watchdog driver
  2008-06-01 16:40 AT91SAM9/CAP9 watchdog driver Andrew Victor
  2008-06-02  6:58 ` Alan Cox
  2008-06-03 21:23 ` Andrew Morton
@ 2008-06-07  6:39 ` David Brownell
  2 siblings, 0 replies; 10+ messages in thread
From: David Brownell @ 2008-06-07  6:39 UTC (permalink / raw)
  To: Andrew Victor; +Cc: linux-arm-kernel, akpm, wim, Linux Kernel list

I thought I'd finally get around to trying this driver.
No luck.

The proximate cause is that Atmel's second stage "at91boot"
loader disables the watchdog.  That's because the reset state
of this watchdog is "reset after 16 seconds" ... so it must
be tended carefully until the Linux "watchdog" daemon takes
over.  Since there's no code in at91boot, U-Boot, or Linux to
do that, it gets disabled.  (How was this driver tested??)

Needless to say, this isn't exactly my model of how to make
a useful watchdog.  That "write once" rule is pure trouble.

I suggest merging the following patch, to reduce confusion.

- Dave


======== CUT HERE
The at91sam9 watchdog is a kind of annoying bit of hardware:  since its
mode register is write-once, it can't be reconfigured.  Moreover, Atmel's
standard second stage loader "at91boot" always this watchdog (at least
on Atmel's reference boards), ensuring that Linux normally can't use it.

This patch removes some confusion by not registering the watchdog device
on systems where it was disabled before Linux starts.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

--- a/arch/arm/mach-at91/at91sam9260_devices.c	2008-06-06 15:00:06.000000000 -0700
+++ b/arch/arm/mach-at91/at91sam9260_devices.c	2008-06-06 20:40:38.000000000 -0700
@@ -21,6 +21,7 @@
 #include <asm/arch/at91sam9260.h>
 #include <asm/arch/at91sam9260_matrix.h>
 #include <asm/arch/at91sam9_smc.h>
+#include <asm/arch/at91_wdt.h>
 
 #include "generic.h"
 
@@ -666,6 +667,9 @@ static struct platform_device at91sam926
 
 static void __init at91_add_device_watchdog(void)
 {
+	/* WDT_MR is write-once; if it was disabled, we're stuck */
+	if (at91_sys_read(AT91_WDT_MR) & AT91_WDT_WDDIS)
+		return;
 	platform_device_register(&at91sam9260_wdt_device);
 }
 #else
--- a/arch/arm/mach-at91/at91sam9261_devices.c	2008-06-06 15:00:06.000000000 -0700
+++ b/arch/arm/mach-at91/at91sam9261_devices.c	2008-06-06 20:40:45.000000000 -0700
@@ -25,6 +25,7 @@
 #include <asm/arch/at91sam9261.h>
 #include <asm/arch/at91sam9261_matrix.h>
 #include <asm/arch/at91sam9_smc.h>
+#include <asm/arch/at91_wdt.h>
 
 #include "generic.h"
 
@@ -654,6 +655,9 @@ static struct platform_device at91sam926
 
 static void __init at91_add_device_watchdog(void)
 {
+	/* WDT_MR is write-once; if it was disabled, we're stuck */
+	if (at91_sys_read(AT91_WDT_MR) & AT91_WDT_WDDIS)
+		return;
 	platform_device_register(&at91sam9261_wdt_device);
 }
 #else
--- a/arch/arm/mach-at91/at91sam9263_devices.c	2008-06-06 15:00:06.000000000 -0700
+++ b/arch/arm/mach-at91/at91sam9263_devices.c	2008-06-06 20:40:48.000000000 -0700
@@ -24,6 +24,7 @@
 #include <asm/arch/at91sam9263.h>
 #include <asm/arch/at91sam9263_matrix.h>
 #include <asm/arch/at91sam9_smc.h>
+#include <asm/arch/at91_wdt.h>
 
 #include "generic.h"
 
@@ -911,6 +912,9 @@ static struct platform_device at91sam926
 
 static void __init at91_add_device_watchdog(void)
 {
+	/* WDT_MR is write-once; if it was disabled, we're stuck */
+	if (at91_sys_read(AT91_WDT_MR) & AT91_WDT_WDDIS)
+		return;
 	platform_device_register(&at91sam9263_wdt_device);
 }
 #else
--- a/arch/arm/mach-at91/at91sam9rl_devices.c	2008-06-06 15:00:06.000000000 -0700
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c	2008-06-06 20:40:52.000000000 -0700
@@ -21,6 +21,7 @@
 #include <asm/arch/at91sam9rl.h>
 #include <asm/arch/at91sam9rl_matrix.h>
 #include <asm/arch/at91sam9_smc.h>
+#include <asm/arch/at91_wdt.h>
 
 #include "generic.h"
 
@@ -501,6 +502,9 @@ static struct platform_device at91sam9rl
 
 static void __init at91_add_device_watchdog(void)
 {
+	/* WDT_MR is write-once; if it was disabled, we're stuck */
+	if (at91_sys_read(AT91_WDT_MR) & AT91_WDT_WDDIS)
+		return;
 	platform_device_register(&at91sam9rl_wdt_device);
 }
 #else



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2008-06-07  6:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-01 16:40 AT91SAM9/CAP9 watchdog driver Andrew Victor
2008-06-02  6:58 ` Alan Cox
2008-06-03 21:23 ` Andrew Morton
2008-06-04  7:31   ` Andrew Victor
2008-06-04 11:36     ` Alan Cox
2008-06-04 18:36       ` Andrew Victor
2008-06-04 18:24         ` Alan Cox
2008-06-04 19:02           ` Andrew Victor
2008-06-04 19:18             ` Alan Cox
2008-06-07  6:39 ` David Brownell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox