--- a/arch/arm/mach-sl2312/sl3516_device.c
+++ b/arch/arm/mach-sl2312/sl3516_device.c
@@ -76,9 +76,30 @@
 	.resource       = sl3516_sata0_resources,
 };
 
+static struct resource sl351x_wdt_resources[] = {
+	[0] = {
+		.start  = SL2312_WAQTCHDOG_BASE + 0x00,
+		.end    = SL2312_WAQTCHDOG_BASE + 0x1C,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = IRQ_WATCHDOG,
+		.end    = IRQ_WATCHDOG,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device sl351x_wdt = {
+	.name		= "sl351x-wdt",
+	.id		= -1,
+	.resource	= sl351x_wdt_resources,
+	.num_resources	= ARRAY_SIZE(sl351x_wdt_resources),
+};
+
 static struct platform_device *sata_devices[] __initdata = {
 	&sata_device,
 	&sata0_device,
+	&sl351x_wdt,
 };
 
 static int __init sl3516_init(void)
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -171,6 +171,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ep93xx_wdt.
 
+config WATCHDOG_SL351X
+	tristate "SL351x Watchdog"
+	depends on WATCHDOG && ARCH_SL2312
+	help
+	  This driver adds watchdog support for the integrated watchdog in the
+	  SL351x processors (Farraday core). If you have one of these processors
+	  and wish to have watchdog support enabled, say Y, otherwise say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sl351x_wdt.
+
 config OMAP_WATCHDOG
 	tristate "OMAP Watchdog"
 	depends on ARCH_OMAP16XX || ARCH_OMAP24XX
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -36,6 +36,7 @@
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
+obj-$(CONFIG_WATCHDOG_SL351X) += sl351x_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
--- /dev/null
+++ b/drivers/char/watchdog/sl351x_wdt.c
@@ -0,0 +1,332 @@
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+#include <asm/arch/sl2312.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/watchdog.h>
+#include <asm/io.h>
+#include <linux/interrupt.h>
+
+#define WATCHDOG_TEST 1
+#define PFX "sl351x-wdt: "
+
+#define _WATCHDOG_COUNTER  0x00
+#define _WATCHDOG_LOAD     0x04
+#define _WATCHDOG_RESTART  0x08
+#define _WATCHDOG_CR       0x0C
+#define _WATCHDOG_STATUS   0x10
+#define _WATCHDOG_CLEAR    0x14
+#define _WATCHDOG_INTRLEN  0x18
+
+static struct resource  *wdt_mem;
+static struct resource  *wdt_irq;
+static void __iomem     *wdt_base;
+static int 		wdt_margin = WATCHDOG_TIMEOUT_MARGIN;	/* in range of 0 .. 60s */
+
+static int open_state = WATCHDOG_DRIVER_CLOSE;
+static int wd_expire = 0;
+
+static void watchdog_enable(void)
+{
+	unsigned long wdcr;
+
+	wdcr = readl(wdt_base + _WATCHDOG_CR);
+	wdcr |= (WATCHDOG_WDENABLE_MSK|WATCHDOG_WDRST_MSK);
+#ifdef WATCHDOG_TEST
+	wdcr |= WATCHDOG_WDINTR_MSK;
+//	wdcr &= ~WATCHDOG_WDRST_MSK;
+#endif
+	wdcr &= ~WATCHDOG_WDCLOCK_MSK;
+	writel(wdcr, wdt_base + _WATCHDOG_CR);
+}
+
+static void watchdog_set_timeout(unsigned long timeout)
+{
+	timeout = WATCHDOG_TIMEOUT_SCALE * timeout;
+	writel(timeout, wdt_base + _WATCHDOG_LOAD);
+	writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
+}
+
+static void watchdog_keepalive(void)
+{
+	writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
+}
+
+static void watchdog_disable(void)
+{
+	unsigned long wdcr;
+
+	wdcr = readl(wdt_base + _WATCHDOG_CR);
+	wdcr &= ~WATCHDOG_WDENABLE_MSK;
+	writel(wdcr, wdt_base + _WATCHDOG_CR);
+}
+
+
+#ifdef WATCHDOG_TEST
+static irqreturn_t watchdog_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned int clear;
+
+	writel(WATCHDOG_CLEAR_STATUS, wdt_base + _WATCHDOG_CLEAR);
+	printk(KERN_INFO PFX "Watchdog timeout, resetting system...\n");
+
+	clear = __raw_readl(IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x0C);
+	clear &= 0x01;
+	__raw_writel(clear,IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x08);
+	wd_expire = 1;
+	return IRQ_HANDLED;
+}
+
+#endif
+
+#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
+static struct watchdog_info sl351x_wdt_ident = {
+	.options          =     OPTIONS,
+	.firmware_version =     0,
+	.identity         =     "sl351x Watchdog",
+};
+
+struct file_operations watchdog_fops = {
+	.write		= watchdog_write,
+	.read		= watchdog_read,
+	.open		= watchdog_open,
+	.release	= watchdog_release,
+	.ioctl		= watchdog_ioctl,
+};
+
+static int watchdog_open(struct inode *inode, struct file *filp)
+{
+	if (open_state == WATCHDOG_DRIVER_OPEN)
+		return -EBUSY;
+
+	wd_expire = 0;
+
+	watchdog_disable();
+	watchdog_set_timeout(wdt_margin);
+	watchdog_enable();
+
+	printk(KERN_INFO PFX "watchog timer enabled, margin: %ds.\n", wdt_margin);
+	open_state = WATCHDOG_DRIVER_OPEN;
+
+	return nonseekable_open(inode, filp);
+}
+
+static int watchdog_release(struct inode *inode, struct file *filp)
+{
+	watchdog_disable();
+
+	open_state = WATCHDOG_DRIVER_CLOSE;
+	wd_expire = 0;
+	printk(KERN_INFO PFX "watchog timer disabled, margin: %ds.\n", wdt_margin);
+
+	return 0;
+}
+
+static ssize_t watchdog_read(struct file *filp, char *buf, size_t count, loff_t *off)
+{
+	int i;
+	unsigned long val;
+
+
+	for(i=0;i< count;i++)
+	{
+		if ((i%4)==0)
+			val = *((unsigned long *)WATCHDOG_COUNTER);
+		buf[i] = (val & 0xFF);
+		val >>= 8;
+	}
+	return count;
+}
+
+static ssize_t watchdog_write(struct file *filp, const char *buf, size_t len, loff_t *off)
+{
+	/*  Refresh the timer. */
+	if (len) {
+		watchdog_keepalive();
+	}
+	return len;
+
+}
+
+static int watchdog_ioctl(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int margin;
+
+	switch(cmd)
+	{
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(argp, &sl351x_wdt_ident,
+				    sizeof(sl351x_wdt_ident)) ? -EFAULT : 0;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, (int __user*)argp);
+
+	case WDIOC_KEEPALIVE:
+		watchdog_keepalive();
+		return 0;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(margin, (int __user*)argp))
+			return -EFAULT;
+
+		/* Arbitrary, can't find the card's limits */
+		if ((margin < 0) || (margin > 60))
+			return -EINVAL;
+
+		// watchdog_disable();
+		wdt_margin = margin;
+		watchdog_set_timeout(margin);
+		watchdog_keepalive();
+		// watchdog_enable();
+
+		/* Fall through */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(wdt_margin, (int *)arg);
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static struct miscdevice wd_dev= {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&watchdog_fops
+};
+
+static char banner[] __initdata = KERN_INFO "SL351x Watchdog Timer, (c) 2007 WILIBOX\n";
+
+static int sl351x_wdt_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret, size;
+	unsigned long wdcr;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		printk(KERN_INFO PFX "failed to get memory region resouce\n");
+		return -ENOMEM;
+	}
+
+	size = (res->end-res->start)+1;
+
+	wdt_mem = request_mem_region(res->start, size, pdev->name);
+	if (wdt_mem == NULL) {
+		printk(KERN_INFO PFX "failed to get memory region\n");
+		return -ENOENT;
+	}
+
+	wdt_base = ioremap(res->start, size);
+	if (wdt_base == NULL) {
+		printk(KERN_INFO PFX "failed to ioremap() region\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		 printk(KERN_INFO PFX "failed to get irq resource\n");
+		 return -ENOENT;
+	}
+
+	wdt_irq = res;
+
+	ret = request_irq(res->start, watchdog_irq, 0, pdev->name, pdev);
+	if (ret != 0) {
+		printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
+		return ret;
+	}
+
+	wdcr = readl(wdt_base + _WATCHDOG_CR);
+	if (wdcr & WATCHDOG_WDENABLE_MSK) {
+		printk(KERN_INFO PFX "Found watchdog in enabled state, reseting ...\n");
+		wdcr &= ~WATCHDOG_WDENABLE_MSK;
+		writel(wdcr, wdt_base + _WATCHDOG_CR);
+	}
+
+	ret = misc_register(&wd_dev);
+
+	return ret;
+}
+
+static int sl351x_wdt_remove(struct platform_device *pdev)
+{
+	if (wdt_base != NULL) {
+		iounmap(wdt_base);
+		wdt_base = NULL;
+	}
+
+	if (wdt_irq != NULL) {
+		free_irq(wdt_irq->start, pdev);
+		release_resource(wdt_irq);
+		wdt_irq = NULL;
+	}
+
+	if (wdt_mem != NULL) {
+		release_resource(wdt_mem);
+		wdt_mem = NULL;
+	}
+
+	misc_deregister(&wd_dev);
+
+	return 0;
+}
+
+static void sl351x_wdt_shutdown(struct platform_device *dev)
+{
+	watchdog_disable();
+}
+
+#ifdef CONFIG_PM
+static int sl351x_wdt_suspend(struct platform_device *dev, pm_message_t state)
+{
+	watchdog_disable();
+}
+
+static int sl351x_wdt_resume(struct platform_device *dev)
+{
+	watchdog_set_timeout(wdt_margin);
+	watchdog_enable();
+}
+
+#else
+#define sl351x_wdt_suspend	NULL
+#define sl351x_wdt_resume	NULL
+#endif
+
+static struct platform_driver sl351x_wdt_driver = {
+	.probe          = sl351x_wdt_probe,
+	.remove         = sl351x_wdt_remove,
+	.shutdown       = sl351x_wdt_shutdown,
+	.suspend        = sl351x_wdt_suspend,
+	.resume         = sl351x_wdt_resume,
+	.driver         = {
+		.owner  = THIS_MODULE,
+		.name   = "sl351x-wdt",
+	},
+};
+
+static int __init watchdog_init(void)
+{
+	printk(banner);
+	return platform_driver_register(&sl351x_wdt_driver);
+}
+
+static void __exit watchdog_exit(void)
+{
+	platform_driver_unregister(&sl351x_wdt_driver);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
