* refresh storm patches * disable BX in uClibc config, add ethernet and watchdog...
[openwrt/openwrt.git] / target / linux / storm / patches / 1022-watchdog.patch
1 --- a/arch/arm/mach-sl2312/sl3516_device.c
2 +++ b/arch/arm/mach-sl2312/sl3516_device.c
3 @@ -76,9 +76,30 @@
4 .resource = sl3516_sata0_resources,
5 };
6
7 +static struct resource sl351x_wdt_resources[] = {
8 + [0] = {
9 + .start = SL2312_WAQTCHDOG_BASE + 0x00,
10 + .end = SL2312_WAQTCHDOG_BASE + 0x1C,
11 + .flags = IORESOURCE_MEM,
12 + },
13 + [1] = {
14 + .start = IRQ_WATCHDOG,
15 + .end = IRQ_WATCHDOG,
16 + .flags = IORESOURCE_IRQ,
17 + },
18 +};
19 +
20 +static struct platform_device sl351x_wdt = {
21 + .name = "sl351x-wdt",
22 + .id = -1,
23 + .resource = sl351x_wdt_resources,
24 + .num_resources = ARRAY_SIZE(sl351x_wdt_resources),
25 +};
26 +
27 static struct platform_device *sata_devices[] __initdata = {
28 &sata_device,
29 &sata0_device,
30 + &sl351x_wdt,
31 };
32
33 static int __init sl3516_init(void)
34 --- a/drivers/char/watchdog/Kconfig
35 +++ b/drivers/char/watchdog/Kconfig
36 @@ -171,6 +171,17 @@
37 To compile this driver as a module, choose M here: the
38 module will be called ep93xx_wdt.
39
40 +config WATCHDOG_SL351X
41 + tristate "SL351x Watchdog"
42 + depends on WATCHDOG && ARCH_SL2312
43 + help
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.
47 +
48 + To compile this driver as a module, choose M here: the
49 + module will be called sl351x_wdt.
50 +
51 config OMAP_WATCHDOG
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 @@
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
64 --- /dev/null
65 +++ b/drivers/char/watchdog/sl351x_wdt.c
66 @@ -0,0 +1,332 @@
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>
81 +#include <asm/io.h>
82 +#include <linux/interrupt.h>
83 +
84 +#define WATCHDOG_TEST 1
85 +#define PFX "sl351x-wdt: "
86 +
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
94 +
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 */
99 +
100 +static int open_state = WATCHDOG_DRIVER_CLOSE;
101 +static int wd_expire = 0;
102 +
103 +static void watchdog_enable(void)
104 +{
105 + unsigned long wdcr;
106 +
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;
112 +#endif
113 + wdcr &= ~WATCHDOG_WDCLOCK_MSK;
114 + writel(wdcr, wdt_base + _WATCHDOG_CR);
115 +}
116 +
117 +static void watchdog_set_timeout(unsigned long timeout)
118 +{
119 + timeout = WATCHDOG_TIMEOUT_SCALE * timeout;
120 + writel(timeout, wdt_base + _WATCHDOG_LOAD);
121 + writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
122 +}
123 +
124 +static void watchdog_keepalive(void)
125 +{
126 + writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
127 +}
128 +
129 +static void watchdog_disable(void)
130 +{
131 + unsigned long wdcr;
132 +
133 + wdcr = readl(wdt_base + _WATCHDOG_CR);
134 + wdcr &= ~WATCHDOG_WDENABLE_MSK;
135 + writel(wdcr, wdt_base + _WATCHDOG_CR);
136 +}
137 +
138 +
139 +#ifdef WATCHDOG_TEST
140 +static irqreturn_t watchdog_irq(int irq, void *dev_id, struct pt_regs *regs)
141 +{
142 + unsigned int clear;
143 +
144 + writel(WATCHDOG_CLEAR_STATUS, wdt_base + _WATCHDOG_CLEAR);
145 + printk(KERN_INFO PFX "Watchdog timeout, resetting system...\n");
146 +
147 + clear = __raw_readl(IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x0C);
148 + clear &= 0x01;
149 + __raw_writel(clear,IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x08);
150 + wd_expire = 1;
151 + return IRQ_HANDLED;
152 +}
153 +
154 +#endif
155 +
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",
161 +};
162 +
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,
169 +};
170 +
171 +static int watchdog_open(struct inode *inode, struct file *filp)
172 +{
173 + if (open_state == WATCHDOG_DRIVER_OPEN)
174 + return -EBUSY;
175 +
176 + wd_expire = 0;
177 +
178 + watchdog_disable();
179 + watchdog_set_timeout(wdt_margin);
180 + watchdog_enable();
181 +
182 + printk(KERN_INFO PFX "watchog timer enabled, margin: %ds.\n", wdt_margin);
183 + open_state = WATCHDOG_DRIVER_OPEN;
184 +
185 + return nonseekable_open(inode, filp);
186 +}
187 +
188 +static int watchdog_release(struct inode *inode, struct file *filp)
189 +{
190 + watchdog_disable();
191 +
192 + open_state = WATCHDOG_DRIVER_CLOSE;
193 + wd_expire = 0;
194 + printk(KERN_INFO PFX "watchog timer disabled, margin: %ds.\n", wdt_margin);
195 +
196 + return 0;
197 +}
198 +
199 +static ssize_t watchdog_read(struct file *filp, char *buf, size_t count, loff_t *off)
200 +{
201 + int i;
202 + unsigned long val;
203 +
204 +
205 + for(i=0;i< count;i++)
206 + {
207 + if ((i%4)==0)
208 + val = *((unsigned long *)WATCHDOG_COUNTER);
209 + buf[i] = (val & 0xFF);
210 + val >>= 8;
211 + }
212 + return count;
213 +}
214 +
215 +static ssize_t watchdog_write(struct file *filp, const char *buf, size_t len, loff_t *off)
216 +{
217 + /* Refresh the timer. */
218 + if (len) {
219 + watchdog_keepalive();
220 + }
221 + return len;
222 +
223 +}
224 +
225 +static int watchdog_ioctl(struct inode *inode, struct file *filp,
226 + unsigned int cmd, unsigned long arg)
227 +{
228 + void __user *argp = (void __user *)arg;
229 + int margin;
230 +
231 + switch(cmd)
232 + {
233 + case WDIOC_GETSUPPORT:
234 + return copy_to_user(argp, &sl351x_wdt_ident,
235 + sizeof(sl351x_wdt_ident)) ? -EFAULT : 0;
236 +
237 + case WDIOC_GETSTATUS:
238 + case WDIOC_GETBOOTSTATUS:
239 + return put_user(0, (int __user*)argp);
240 +
241 + case WDIOC_KEEPALIVE:
242 + watchdog_keepalive();
243 + return 0;
244 +
245 + case WDIOC_SETTIMEOUT:
246 + if (get_user(margin, (int __user*)argp))
247 + return -EFAULT;
248 +
249 + /* Arbitrary, can't find the card's limits */
250 + if ((margin < 0) || (margin > 60))
251 + return -EINVAL;
252 +
253 + // watchdog_disable();
254 + wdt_margin = margin;
255 + watchdog_set_timeout(margin);
256 + watchdog_keepalive();
257 + // watchdog_enable();
258 +
259 + /* Fall through */
260 +
261 + case WDIOC_GETTIMEOUT:
262 + return put_user(wdt_margin, (int *)arg);
263 +
264 + default:
265 + return -ENOIOCTLCMD;
266 + }
267 +}
268 +
269 +static struct miscdevice wd_dev= {
270 + WATCHDOG_MINOR,
271 + "watchdog",
272 + &watchdog_fops
273 +};
274 +
275 +static char banner[] __initdata = KERN_INFO "SL351x Watchdog Timer, (c) 2007 WILIBOX\n";
276 +
277 +static int sl351x_wdt_probe(struct platform_device *pdev)
278 +{
279 + struct resource *res;
280 + int ret, size;
281 + unsigned long wdcr;
282 +
283 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
284 + if (res == NULL) {
285 + printk(KERN_INFO PFX "failed to get memory region resouce\n");
286 + return -ENOMEM;
287 + }
288 +
289 + size = (res->end-res->start)+1;
290 +
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");
294 + return -ENOENT;
295 + }
296 +
297 + wdt_base = ioremap(res->start, size);
298 + if (wdt_base == NULL) {
299 + printk(KERN_INFO PFX "failed to ioremap() region\n");
300 + return -EINVAL;
301 + }
302 +
303 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
304 + if (res == NULL) {
305 + printk(KERN_INFO PFX "failed to get irq resource\n");
306 + return -ENOENT;
307 + }
308 +
309 + wdt_irq = res;
310 +
311 + ret = request_irq(res->start, watchdog_irq, 0, pdev->name, pdev);
312 + if (ret != 0) {
313 + printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
314 + return ret;
315 + }
316 +
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);
322 + }
323 +
324 + ret = misc_register(&wd_dev);
325 +
326 + return ret;
327 +}
328 +
329 +static int sl351x_wdt_remove(struct platform_device *pdev)
330 +{
331 + if (wdt_base != NULL) {
332 + iounmap(wdt_base);
333 + wdt_base = NULL;
334 + }
335 +
336 + if (wdt_irq != NULL) {
337 + free_irq(wdt_irq->start, pdev);
338 + release_resource(wdt_irq);
339 + wdt_irq = NULL;
340 + }
341 +
342 + if (wdt_mem != NULL) {
343 + release_resource(wdt_mem);
344 + wdt_mem = NULL;
345 + }
346 +
347 + misc_deregister(&wd_dev);
348 +
349 + return 0;
350 +}
351 +
352 +static void sl351x_wdt_shutdown(struct platform_device *dev)
353 +{
354 + watchdog_disable();
355 +}
356 +
357 +#ifdef CONFIG_PM
358 +static int sl351x_wdt_suspend(struct platform_device *dev, pm_message_t state)
359 +{
360 + watchdog_disable();
361 +}
362 +
363 +static int sl351x_wdt_resume(struct platform_device *dev)
364 +{
365 + watchdog_set_timeout(wdt_margin);
366 + watchdog_enable();
367 +}
368 +
369 +#else
370 +#define sl351x_wdt_suspend NULL
371 +#define sl351x_wdt_resume NULL
372 +#endif
373 +
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,
380 + .driver = {
381 + .owner = THIS_MODULE,
382 + .name = "sl351x-wdt",
383 + },
384 +};
385 +
386 +static int __init watchdog_init(void)
387 +{
388 + printk(banner);
389 + return platform_driver_register(&sl351x_wdt_driver);
390 +}
391 +
392 +static void __exit watchdog_exit(void)
393 +{
394 + platform_driver_unregister(&sl351x_wdt_driver);
395 +}
396 +
397 +module_init(watchdog_init);
398 +module_exit(watchdog_exit);