1 --- a/arch/arm/mach-sl2312/sl3516_device.c
2 +++ b/arch/arm/mach-sl2312/sl3516_device.c
3 @@ -76,9 +76,30 @@ static struct platform_device sata0_devi
4 .resource = sl3516_sata0_resources,
7 +static struct resource sl351x_wdt_resources[] = {
9 + .start = SL2312_WAQTCHDOG_BASE + 0x00,
10 + .end = SL2312_WAQTCHDOG_BASE + 0x1C,
11 + .flags = IORESOURCE_MEM,
14 + .start = IRQ_WATCHDOG,
15 + .end = IRQ_WATCHDOG,
16 + .flags = IORESOURCE_IRQ,
20 +static struct platform_device sl351x_wdt = {
21 + .name = "sl351x-wdt",
23 + .resource = sl351x_wdt_resources,
24 + .num_resources = ARRAY_SIZE(sl351x_wdt_resources),
27 static struct platform_device *sata_devices[] __initdata = {
33 static int __init sl3516_init(void)
34 --- a/drivers/char/watchdog/Kconfig
35 +++ b/drivers/char/watchdog/Kconfig
36 @@ -171,6 +171,17 @@ config EP93XX_WATCHDOG
37 To compile this driver as a module, choose M here: the
38 module will be called ep93xx_wdt.
40 +config WATCHDOG_SL351X
41 + tristate "SL351x Watchdog"
42 + depends on WATCHDOG && ARCH_SL2312
44 + This driver adds watchdog support for the integrated watchdog in the
45 + SL351x processors (Farraday core). If you have one of these processors
46 + and wish to have watchdog support enabled, say Y, otherwise say N.
48 + To compile this driver as a module, choose M here: the
49 + module will be called sl351x_wdt.
52 tristate "OMAP Watchdog"
53 depends on ARCH_OMAP16XX || ARCH_OMAP24XX
54 --- a/drivers/char/watchdog/Makefile
55 +++ b/drivers/char/watchdog/Makefile
56 @@ -36,6 +36,7 @@ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c241
57 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
58 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
59 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
60 +obj-$(CONFIG_WATCHDOG_SL351X) += sl351x_wdt.o
61 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
62 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
63 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
65 +++ b/drivers/char/watchdog/sl351x_wdt.c
67 +#include <linux/module.h>
68 +#include <linux/types.h>
69 +#include <linux/fs.h>
70 +#include <linux/mm.h>
71 +#include <linux/errno.h>
72 +#include <linux/init.h>
73 +#include <linux/miscdevice.h>
74 +#include <linux/watchdog.h>
75 +#include <linux/platform_device.h>
76 +#include <asm/uaccess.h>
77 +#include <asm/arch/sl2312.h>
78 +#include <asm/arch/hardware.h>
79 +#include <asm/arch/irqs.h>
80 +#include <asm/arch/watchdog.h>
82 +#include <linux/interrupt.h>
84 +#define WATCHDOG_TEST 1
85 +#define PFX "sl351x-wdt: "
87 +#define _WATCHDOG_COUNTER 0x00
88 +#define _WATCHDOG_LOAD 0x04
89 +#define _WATCHDOG_RESTART 0x08
90 +#define _WATCHDOG_CR 0x0C
91 +#define _WATCHDOG_STATUS 0x10
92 +#define _WATCHDOG_CLEAR 0x14
93 +#define _WATCHDOG_INTRLEN 0x18
95 +static struct resource *wdt_mem;
96 +static struct resource *wdt_irq;
97 +static void __iomem *wdt_base;
98 +static int wdt_margin = WATCHDOG_TIMEOUT_MARGIN; /* in range of 0 .. 60s */
100 +static int open_state = WATCHDOG_DRIVER_CLOSE;
101 +static int wd_expire = 0;
103 +static void watchdog_enable(void)
105 + unsigned long wdcr;
107 + wdcr = readl(wdt_base + _WATCHDOG_CR);
108 + wdcr |= (WATCHDOG_WDENABLE_MSK|WATCHDOG_WDRST_MSK);
109 +#ifdef WATCHDOG_TEST
110 + wdcr |= WATCHDOG_WDINTR_MSK;
111 +// wdcr &= ~WATCHDOG_WDRST_MSK;
113 + wdcr &= ~WATCHDOG_WDCLOCK_MSK;
114 + writel(wdcr, wdt_base + _WATCHDOG_CR);
117 +static void watchdog_set_timeout(unsigned long timeout)
119 + timeout = WATCHDOG_TIMEOUT_SCALE * timeout;
120 + writel(timeout, wdt_base + _WATCHDOG_LOAD);
121 + writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
124 +static void watchdog_keepalive(void)
126 + writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
129 +static void watchdog_disable(void)
131 + unsigned long wdcr;
133 + wdcr = readl(wdt_base + _WATCHDOG_CR);
134 + wdcr &= ~WATCHDOG_WDENABLE_MSK;
135 + writel(wdcr, wdt_base + _WATCHDOG_CR);
139 +#ifdef WATCHDOG_TEST
140 +static irqreturn_t watchdog_irq(int irq, void *dev_id, struct pt_regs *regs)
142 + unsigned int clear;
144 + writel(WATCHDOG_CLEAR_STATUS, wdt_base + _WATCHDOG_CLEAR);
145 + printk(KERN_INFO PFX "Watchdog timeout, resetting system...\n");
147 + clear = __raw_readl(IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x0C);
149 + __raw_writel(clear,IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x08);
151 + return IRQ_HANDLED;
156 +#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
157 +static struct watchdog_info sl351x_wdt_ident = {
158 + .options = OPTIONS,
159 + .firmware_version = 0,
160 + .identity = "sl351x Watchdog",
163 +struct file_operations watchdog_fops = {
164 + .write = watchdog_write,
165 + .read = watchdog_read,
166 + .open = watchdog_open,
167 + .release = watchdog_release,
168 + .ioctl = watchdog_ioctl,
171 +static int watchdog_open(struct inode *inode, struct file *filp)
173 + if (open_state == WATCHDOG_DRIVER_OPEN)
178 + watchdog_disable();
179 + watchdog_set_timeout(wdt_margin);
182 + printk(KERN_INFO PFX "watchog timer enabled, margin: %ds.\n", wdt_margin);
183 + open_state = WATCHDOG_DRIVER_OPEN;
185 + return nonseekable_open(inode, filp);
188 +static int watchdog_release(struct inode *inode, struct file *filp)
190 + watchdog_disable();
192 + open_state = WATCHDOG_DRIVER_CLOSE;
194 + printk(KERN_INFO PFX "watchog timer disabled, margin: %ds.\n", wdt_margin);
199 +static ssize_t watchdog_read(struct file *filp, char *buf, size_t count, loff_t *off)
205 + for(i=0;i< count;i++)
208 + val = *((unsigned long *)WATCHDOG_COUNTER);
209 + buf[i] = (val & 0xFF);
215 +static ssize_t watchdog_write(struct file *filp, const char *buf, size_t len, loff_t *off)
217 + /* Refresh the timer. */
219 + watchdog_keepalive();
225 +static int watchdog_ioctl(struct inode *inode, struct file *filp,
226 + unsigned int cmd, unsigned long arg)
228 + void __user *argp = (void __user *)arg;
233 + case WDIOC_GETSUPPORT:
234 + return copy_to_user(argp, &sl351x_wdt_ident,
235 + sizeof(sl351x_wdt_ident)) ? -EFAULT : 0;
237 + case WDIOC_GETSTATUS:
238 + case WDIOC_GETBOOTSTATUS:
239 + return put_user(0, (int __user*)argp);
241 + case WDIOC_KEEPALIVE:
242 + watchdog_keepalive();
245 + case WDIOC_SETTIMEOUT:
246 + if (get_user(margin, (int __user*)argp))
249 + /* Arbitrary, can't find the card's limits */
250 + if ((margin < 0) || (margin > 60))
253 + // watchdog_disable();
254 + wdt_margin = margin;
255 + watchdog_set_timeout(margin);
256 + watchdog_keepalive();
257 + // watchdog_enable();
261 + case WDIOC_GETTIMEOUT:
262 + return put_user(wdt_margin, (int *)arg);
265 + return -ENOIOCTLCMD;
269 +static struct miscdevice wd_dev= {
275 +static char banner[] __initdata = KERN_INFO "SL351x Watchdog Timer, (c) 2007 WILIBOX\n";
277 +static int sl351x_wdt_probe(struct platform_device *pdev)
279 + struct resource *res;
281 + unsigned long wdcr;
283 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
285 + printk(KERN_INFO PFX "failed to get memory region resouce\n");
289 + size = (res->end-res->start)+1;
291 + wdt_mem = request_mem_region(res->start, size, pdev->name);
292 + if (wdt_mem == NULL) {
293 + printk(KERN_INFO PFX "failed to get memory region\n");
297 + wdt_base = ioremap(res->start, size);
298 + if (wdt_base == NULL) {
299 + printk(KERN_INFO PFX "failed to ioremap() region\n");
303 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
305 + printk(KERN_INFO PFX "failed to get irq resource\n");
311 + ret = request_irq(res->start, watchdog_irq, 0, pdev->name, pdev);
313 + printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
317 + wdcr = readl(wdt_base + _WATCHDOG_CR);
318 + if (wdcr & WATCHDOG_WDENABLE_MSK) {
319 + printk(KERN_INFO PFX "Found watchdog in enabled state, reseting ...\n");
320 + wdcr &= ~WATCHDOG_WDENABLE_MSK;
321 + writel(wdcr, wdt_base + _WATCHDOG_CR);
324 + ret = misc_register(&wd_dev);
329 +static int sl351x_wdt_remove(struct platform_device *pdev)
331 + if (wdt_base != NULL) {
336 + if (wdt_irq != NULL) {
337 + free_irq(wdt_irq->start, pdev);
338 + release_resource(wdt_irq);
342 + if (wdt_mem != NULL) {
343 + release_resource(wdt_mem);
347 + misc_deregister(&wd_dev);
352 +static void sl351x_wdt_shutdown(struct platform_device *dev)
354 + watchdog_disable();
358 +static int sl351x_wdt_suspend(struct platform_device *dev, pm_message_t state)
360 + watchdog_disable();
363 +static int sl351x_wdt_resume(struct platform_device *dev)
365 + watchdog_set_timeout(wdt_margin);
370 +#define sl351x_wdt_suspend NULL
371 +#define sl351x_wdt_resume NULL
374 +static struct platform_driver sl351x_wdt_driver = {
375 + .probe = sl351x_wdt_probe,
376 + .remove = sl351x_wdt_remove,
377 + .shutdown = sl351x_wdt_shutdown,
378 + .suspend = sl351x_wdt_suspend,
379 + .resume = sl351x_wdt_resume,
381 + .owner = THIS_MODULE,
382 + .name = "sl351x-wdt",
386 +static int __init watchdog_init(void)
389 + return platform_driver_register(&sl351x_wdt_driver);
392 +static void __exit watchdog_exit(void)
394 + platform_driver_unregister(&sl351x_wdt_driver);
397 +module_init(watchdog_init);
398 +module_exit(watchdog_exit);