xref: /openbmc/linux/drivers/watchdog/rc32434_wdt.c (revision 03ec58568a3c66cac4b23ff74db95c966a1521de)
1*03ec5856SFlorian Fainelli /*
2*03ec5856SFlorian Fainelli  *  IDT Interprise 79RC32434 watchdog driver
3*03ec5856SFlorian Fainelli  *
4*03ec5856SFlorian Fainelli  *  Copyright (C) 2006, Ondrej Zajicek <santiago@crfreenet.org>
5*03ec5856SFlorian Fainelli  *  Copyright (C) 2008, Florian Fainelli <florian@openwrt.org>
6*03ec5856SFlorian Fainelli  *
7*03ec5856SFlorian Fainelli  *  based on
8*03ec5856SFlorian Fainelli  *  SoftDog 0.05:	A Software Watchdog Device
9*03ec5856SFlorian Fainelli  *
10*03ec5856SFlorian Fainelli  *  (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
11*03ec5856SFlorian Fainelli  *
12*03ec5856SFlorian Fainelli  *  This program is free software; you can redistribute it and/or
13*03ec5856SFlorian Fainelli  *  modify it under the terms of the GNU General Public License
14*03ec5856SFlorian Fainelli  *  as published by the Free Software Foundation; either version
15*03ec5856SFlorian Fainelli  *  2 of the License, or (at your option) any later version.
16*03ec5856SFlorian Fainelli  *
17*03ec5856SFlorian Fainelli  */
18*03ec5856SFlorian Fainelli 
19*03ec5856SFlorian Fainelli #include <linux/module.h>
20*03ec5856SFlorian Fainelli #include <linux/types.h>
21*03ec5856SFlorian Fainelli #include <linux/kernel.h>
22*03ec5856SFlorian Fainelli #include <linux/fs.h>
23*03ec5856SFlorian Fainelli #include <linux/mm.h>
24*03ec5856SFlorian Fainelli #include <linux/miscdevice.h>
25*03ec5856SFlorian Fainelli #include <linux/watchdog.h>
26*03ec5856SFlorian Fainelli #include <linux/reboot.h>
27*03ec5856SFlorian Fainelli #include <linux/smp_lock.h>
28*03ec5856SFlorian Fainelli #include <linux/init.h>
29*03ec5856SFlorian Fainelli #include <linux/platform_device.h>
30*03ec5856SFlorian Fainelli #include <linux/uaccess.h>
31*03ec5856SFlorian Fainelli 
32*03ec5856SFlorian Fainelli #include <asm/bootinfo.h>
33*03ec5856SFlorian Fainelli #include <asm/time.h>
34*03ec5856SFlorian Fainelli #include <asm/mach-rc32434/integ.h>
35*03ec5856SFlorian Fainelli 
36*03ec5856SFlorian Fainelli #define MAX_TIMEOUT			20
37*03ec5856SFlorian Fainelli #define RC32434_WDT_INTERVAL		(15 * HZ)
38*03ec5856SFlorian Fainelli 
39*03ec5856SFlorian Fainelli #define VERSION "0.2"
40*03ec5856SFlorian Fainelli 
41*03ec5856SFlorian Fainelli static struct {
42*03ec5856SFlorian Fainelli 	struct completion stop;
43*03ec5856SFlorian Fainelli 	int running;
44*03ec5856SFlorian Fainelli 	struct timer_list timer;
45*03ec5856SFlorian Fainelli 	int queue;
46*03ec5856SFlorian Fainelli 	int default_ticks;
47*03ec5856SFlorian Fainelli 	unsigned long inuse;
48*03ec5856SFlorian Fainelli } rc32434_wdt_device;
49*03ec5856SFlorian Fainelli 
50*03ec5856SFlorian Fainelli static struct integ __iomem *wdt_reg;
51*03ec5856SFlorian Fainelli static int ticks = 100 * HZ;
52*03ec5856SFlorian Fainelli 
53*03ec5856SFlorian Fainelli static int expect_close;
54*03ec5856SFlorian Fainelli static int timeout;
55*03ec5856SFlorian Fainelli 
56*03ec5856SFlorian Fainelli static int nowayout = WATCHDOG_NOWAYOUT;
57*03ec5856SFlorian Fainelli module_param(nowayout, int, 0);
58*03ec5856SFlorian Fainelli MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
59*03ec5856SFlorian Fainelli 	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
60*03ec5856SFlorian Fainelli 
61*03ec5856SFlorian Fainelli 
62*03ec5856SFlorian Fainelli static void rc32434_wdt_start(void)
63*03ec5856SFlorian Fainelli {
64*03ec5856SFlorian Fainelli 	u32 val;
65*03ec5856SFlorian Fainelli 
66*03ec5856SFlorian Fainelli 	if (!rc32434_wdt_device.inuse) {
67*03ec5856SFlorian Fainelli 		writel(0, &wdt_reg->wtcount);
68*03ec5856SFlorian Fainelli 
69*03ec5856SFlorian Fainelli 		val = RC32434_ERR_WRE;
70*03ec5856SFlorian Fainelli 		writel(readl(&wdt_reg->errcs) | val, &wdt_reg->errcs);
71*03ec5856SFlorian Fainelli 
72*03ec5856SFlorian Fainelli 		val = RC32434_WTC_EN;
73*03ec5856SFlorian Fainelli 		writel(readl(&wdt_reg->wtc) | val, &wdt_reg->wtc);
74*03ec5856SFlorian Fainelli 	}
75*03ec5856SFlorian Fainelli 	rc32434_wdt_device.running++;
76*03ec5856SFlorian Fainelli }
77*03ec5856SFlorian Fainelli 
78*03ec5856SFlorian Fainelli static void rc32434_wdt_stop(void)
79*03ec5856SFlorian Fainelli {
80*03ec5856SFlorian Fainelli 	u32 val;
81*03ec5856SFlorian Fainelli 
82*03ec5856SFlorian Fainelli 	if (rc32434_wdt_device.running) {
83*03ec5856SFlorian Fainelli 
84*03ec5856SFlorian Fainelli 		val = ~RC32434_WTC_EN;
85*03ec5856SFlorian Fainelli 		writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc);
86*03ec5856SFlorian Fainelli 
87*03ec5856SFlorian Fainelli 		val = ~RC32434_ERR_WRE;
88*03ec5856SFlorian Fainelli 		writel(readl(&wdt_reg->errcs) & val, &wdt_reg->errcs);
89*03ec5856SFlorian Fainelli 
90*03ec5856SFlorian Fainelli 		rc32434_wdt_device.running = 0;
91*03ec5856SFlorian Fainelli 	}
92*03ec5856SFlorian Fainelli }
93*03ec5856SFlorian Fainelli 
94*03ec5856SFlorian Fainelli static void rc32434_wdt_set(int new_timeout)
95*03ec5856SFlorian Fainelli {
96*03ec5856SFlorian Fainelli 	u32 cmp = new_timeout * HZ;
97*03ec5856SFlorian Fainelli 	u32 state, val;
98*03ec5856SFlorian Fainelli 
99*03ec5856SFlorian Fainelli 	timeout = new_timeout;
100*03ec5856SFlorian Fainelli 	/*
101*03ec5856SFlorian Fainelli 	 * store and disable WTC
102*03ec5856SFlorian Fainelli 	 */
103*03ec5856SFlorian Fainelli 	state = (u32)(readl(&wdt_reg->wtc) & RC32434_WTC_EN);
104*03ec5856SFlorian Fainelli 	val = ~RC32434_WTC_EN;
105*03ec5856SFlorian Fainelli 	writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc);
106*03ec5856SFlorian Fainelli 
107*03ec5856SFlorian Fainelli 	writel(0, &wdt_reg->wtcount);
108*03ec5856SFlorian Fainelli 	writel(cmp, &wdt_reg->wtcompare);
109*03ec5856SFlorian Fainelli 
110*03ec5856SFlorian Fainelli 	/*
111*03ec5856SFlorian Fainelli 	 * restore WTC
112*03ec5856SFlorian Fainelli 	 */
113*03ec5856SFlorian Fainelli 
114*03ec5856SFlorian Fainelli 	writel(readl(&wdt_reg->wtc) | state, &wdt_reg);
115*03ec5856SFlorian Fainelli }
116*03ec5856SFlorian Fainelli 
117*03ec5856SFlorian Fainelli static void rc32434_wdt_reset(void)
118*03ec5856SFlorian Fainelli {
119*03ec5856SFlorian Fainelli 	ticks = rc32434_wdt_device.default_ticks;
120*03ec5856SFlorian Fainelli }
121*03ec5856SFlorian Fainelli 
122*03ec5856SFlorian Fainelli static void rc32434_wdt_update(unsigned long unused)
123*03ec5856SFlorian Fainelli {
124*03ec5856SFlorian Fainelli 	if (rc32434_wdt_device.running)
125*03ec5856SFlorian Fainelli 		ticks--;
126*03ec5856SFlorian Fainelli 
127*03ec5856SFlorian Fainelli 	writel(0, &wdt_reg->wtcount);
128*03ec5856SFlorian Fainelli 
129*03ec5856SFlorian Fainelli 	if (rc32434_wdt_device.queue && ticks)
130*03ec5856SFlorian Fainelli 		mod_timer(&rc32434_wdt_device.timer,
131*03ec5856SFlorian Fainelli 			jiffies + RC32434_WDT_INTERVAL);
132*03ec5856SFlorian Fainelli 	else
133*03ec5856SFlorian Fainelli 		complete(&rc32434_wdt_device.stop);
134*03ec5856SFlorian Fainelli }
135*03ec5856SFlorian Fainelli 
136*03ec5856SFlorian Fainelli static int rc32434_wdt_open(struct inode *inode, struct file *file)
137*03ec5856SFlorian Fainelli {
138*03ec5856SFlorian Fainelli 	if (test_and_set_bit(0, &rc32434_wdt_device.inuse))
139*03ec5856SFlorian Fainelli 		return -EBUSY;
140*03ec5856SFlorian Fainelli 
141*03ec5856SFlorian Fainelli 	if (nowayout)
142*03ec5856SFlorian Fainelli 		__module_get(THIS_MODULE);
143*03ec5856SFlorian Fainelli 
144*03ec5856SFlorian Fainelli 	return nonseekable_open(inode, file);
145*03ec5856SFlorian Fainelli }
146*03ec5856SFlorian Fainelli 
147*03ec5856SFlorian Fainelli static int rc32434_wdt_release(struct inode *inode, struct file *file)
148*03ec5856SFlorian Fainelli {
149*03ec5856SFlorian Fainelli 	if (expect_close && nowayout == 0) {
150*03ec5856SFlorian Fainelli 		rc32434_wdt_stop();
151*03ec5856SFlorian Fainelli 		printk(KERN_INFO KBUILD_MODNAME ": disabling watchdog timer\n");
152*03ec5856SFlorian Fainelli 		module_put(THIS_MODULE);
153*03ec5856SFlorian Fainelli 	} else
154*03ec5856SFlorian Fainelli 		printk(KERN_CRIT KBUILD_MODNAME
155*03ec5856SFlorian Fainelli 			": device closed unexpectedly. WDT will not stop !\n");
156*03ec5856SFlorian Fainelli 
157*03ec5856SFlorian Fainelli 	clear_bit(0, &rc32434_wdt_device.inuse);
158*03ec5856SFlorian Fainelli 	return 0;
159*03ec5856SFlorian Fainelli }
160*03ec5856SFlorian Fainelli 
161*03ec5856SFlorian Fainelli static ssize_t rc32434_wdt_write(struct file *file, const char *data,
162*03ec5856SFlorian Fainelli 				size_t len, loff_t *ppos)
163*03ec5856SFlorian Fainelli {
164*03ec5856SFlorian Fainelli 	if (len) {
165*03ec5856SFlorian Fainelli 		if (!nowayout) {
166*03ec5856SFlorian Fainelli 			size_t i;
167*03ec5856SFlorian Fainelli 
168*03ec5856SFlorian Fainelli 			/* In case it was set long ago */
169*03ec5856SFlorian Fainelli 			expect_close = 0;
170*03ec5856SFlorian Fainelli 
171*03ec5856SFlorian Fainelli 			for (i = 0; i != len; i++) {
172*03ec5856SFlorian Fainelli 				char c;
173*03ec5856SFlorian Fainelli 				if (get_user(c, data + i))
174*03ec5856SFlorian Fainelli 					return -EFAULT;
175*03ec5856SFlorian Fainelli 				if (c == 'V')
176*03ec5856SFlorian Fainelli 					expect_close = 1;
177*03ec5856SFlorian Fainelli 			}
178*03ec5856SFlorian Fainelli 		}
179*03ec5856SFlorian Fainelli 		rc32434_wdt_update(0);
180*03ec5856SFlorian Fainelli 		return len;
181*03ec5856SFlorian Fainelli 	}
182*03ec5856SFlorian Fainelli 	return 0;
183*03ec5856SFlorian Fainelli }
184*03ec5856SFlorian Fainelli 
185*03ec5856SFlorian Fainelli static int rc32434_wdt_ioctl(struct inode *inode, struct file *file,
186*03ec5856SFlorian Fainelli 	unsigned int cmd, unsigned long arg)
187*03ec5856SFlorian Fainelli {
188*03ec5856SFlorian Fainelli 	void __user *argp = (void __user *)arg;
189*03ec5856SFlorian Fainelli 	int new_timeout;
190*03ec5856SFlorian Fainelli 	unsigned int value;
191*03ec5856SFlorian Fainelli 	static struct watchdog_info ident = {
192*03ec5856SFlorian Fainelli 		.options =		WDIOF_SETTIMEOUT |
193*03ec5856SFlorian Fainelli 					WDIOF_KEEPALIVEPING |
194*03ec5856SFlorian Fainelli 					WDIOF_MAGICCLOSE,
195*03ec5856SFlorian Fainelli 		.identity =		"RC32434_WDT Watchdog",
196*03ec5856SFlorian Fainelli 	};
197*03ec5856SFlorian Fainelli 	switch (cmd) {
198*03ec5856SFlorian Fainelli 	case WDIOC_KEEPALIVE:
199*03ec5856SFlorian Fainelli 		rc32434_wdt_reset();
200*03ec5856SFlorian Fainelli 		break;
201*03ec5856SFlorian Fainelli 	case WDIOC_GETSTATUS:
202*03ec5856SFlorian Fainelli 	case WDIOC_GETBOOTSTATUS:
203*03ec5856SFlorian Fainelli 		value = readl(&wdt_reg->wtcount);
204*03ec5856SFlorian Fainelli 		if (copy_to_user(argp, &value, sizeof(int)))
205*03ec5856SFlorian Fainelli 			return -EFAULT;
206*03ec5856SFlorian Fainelli 		break;
207*03ec5856SFlorian Fainelli 	case WDIOC_GETSUPPORT:
208*03ec5856SFlorian Fainelli 		if (copy_to_user(argp, &ident, sizeof(ident)))
209*03ec5856SFlorian Fainelli 			return -EFAULT;
210*03ec5856SFlorian Fainelli 		break;
211*03ec5856SFlorian Fainelli 	case WDIOC_SETOPTIONS:
212*03ec5856SFlorian Fainelli 		if (copy_from_user(&value, argp, sizeof(int)))
213*03ec5856SFlorian Fainelli 			return -EFAULT;
214*03ec5856SFlorian Fainelli 		switch (value) {
215*03ec5856SFlorian Fainelli 		case WDIOS_ENABLECARD:
216*03ec5856SFlorian Fainelli 			rc32434_wdt_start();
217*03ec5856SFlorian Fainelli 			break;
218*03ec5856SFlorian Fainelli 		case WDIOS_DISABLECARD:
219*03ec5856SFlorian Fainelli 			rc32434_wdt_stop();
220*03ec5856SFlorian Fainelli 		default:
221*03ec5856SFlorian Fainelli 			return -EINVAL;
222*03ec5856SFlorian Fainelli 		}
223*03ec5856SFlorian Fainelli 		break;
224*03ec5856SFlorian Fainelli 	case WDIOC_SETTIMEOUT:
225*03ec5856SFlorian Fainelli 		if (copy_from_user(&new_timeout, argp, sizeof(int)))
226*03ec5856SFlorian Fainelli 			return -EFAULT;
227*03ec5856SFlorian Fainelli 		if (new_timeout < 1)
228*03ec5856SFlorian Fainelli 			return -EINVAL;
229*03ec5856SFlorian Fainelli 		if (new_timeout > MAX_TIMEOUT)
230*03ec5856SFlorian Fainelli 			return -EINVAL;
231*03ec5856SFlorian Fainelli 		rc32434_wdt_set(new_timeout);
232*03ec5856SFlorian Fainelli 	case WDIOC_GETTIMEOUT:
233*03ec5856SFlorian Fainelli 		return copy_to_user(argp, &timeout, sizeof(int));
234*03ec5856SFlorian Fainelli 	default:
235*03ec5856SFlorian Fainelli 		return -ENOTTY;
236*03ec5856SFlorian Fainelli 	}
237*03ec5856SFlorian Fainelli 
238*03ec5856SFlorian Fainelli 	return 0;
239*03ec5856SFlorian Fainelli }
240*03ec5856SFlorian Fainelli 
241*03ec5856SFlorian Fainelli static struct file_operations rc32434_wdt_fops = {
242*03ec5856SFlorian Fainelli 	.owner		= THIS_MODULE,
243*03ec5856SFlorian Fainelli 	.llseek		= no_llseek,
244*03ec5856SFlorian Fainelli 	.write		= rc32434_wdt_write,
245*03ec5856SFlorian Fainelli 	.ioctl		= rc32434_wdt_ioctl,
246*03ec5856SFlorian Fainelli 	.open		= rc32434_wdt_open,
247*03ec5856SFlorian Fainelli 	.release	= rc32434_wdt_release,
248*03ec5856SFlorian Fainelli };
249*03ec5856SFlorian Fainelli 
250*03ec5856SFlorian Fainelli static struct miscdevice rc32434_wdt_miscdev = {
251*03ec5856SFlorian Fainelli 	.minor	= WATCHDOG_MINOR,
252*03ec5856SFlorian Fainelli 	.name	= "watchdog",
253*03ec5856SFlorian Fainelli 	.fops	= &rc32434_wdt_fops,
254*03ec5856SFlorian Fainelli };
255*03ec5856SFlorian Fainelli 
256*03ec5856SFlorian Fainelli static char banner[] = KERN_INFO KBUILD_MODNAME
257*03ec5856SFlorian Fainelli 		": Watchdog Timer version " VERSION ", timer margin: %d sec\n";
258*03ec5856SFlorian Fainelli 
259*03ec5856SFlorian Fainelli static int rc32434_wdt_probe(struct platform_device *pdev)
260*03ec5856SFlorian Fainelli {
261*03ec5856SFlorian Fainelli 	int ret;
262*03ec5856SFlorian Fainelli 	struct resource *r;
263*03ec5856SFlorian Fainelli 
264*03ec5856SFlorian Fainelli 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb500_wdt_res");
265*03ec5856SFlorian Fainelli 	if (!r) {
266*03ec5856SFlorian Fainelli 		printk(KERN_ERR KBUILD_MODNAME
267*03ec5856SFlorian Fainelli 			"failed to retrieve resources\n");
268*03ec5856SFlorian Fainelli 		return -ENODEV;
269*03ec5856SFlorian Fainelli 	}
270*03ec5856SFlorian Fainelli 
271*03ec5856SFlorian Fainelli 	wdt_reg = ioremap_nocache(r->start, r->end - r->start);
272*03ec5856SFlorian Fainelli 	if (!wdt_reg) {
273*03ec5856SFlorian Fainelli 		printk(KERN_ERR KBUILD_MODNAME
274*03ec5856SFlorian Fainelli 			"failed to remap I/O resources\n");
275*03ec5856SFlorian Fainelli 		return -ENXIO;
276*03ec5856SFlorian Fainelli 	}
277*03ec5856SFlorian Fainelli 
278*03ec5856SFlorian Fainelli 	ret = misc_register(&rc32434_wdt_miscdev);
279*03ec5856SFlorian Fainelli 
280*03ec5856SFlorian Fainelli 	if (ret < 0) {
281*03ec5856SFlorian Fainelli 		printk(KERN_ERR KBUILD_MODNAME
282*03ec5856SFlorian Fainelli 			"failed to register watchdog device\n");
283*03ec5856SFlorian Fainelli 		goto unmap;
284*03ec5856SFlorian Fainelli 	}
285*03ec5856SFlorian Fainelli 
286*03ec5856SFlorian Fainelli 	init_completion(&rc32434_wdt_device.stop);
287*03ec5856SFlorian Fainelli 	rc32434_wdt_device.queue = 0;
288*03ec5856SFlorian Fainelli 
289*03ec5856SFlorian Fainelli 	clear_bit(0, &rc32434_wdt_device.inuse);
290*03ec5856SFlorian Fainelli 
291*03ec5856SFlorian Fainelli 	setup_timer(&rc32434_wdt_device.timer, rc32434_wdt_update, 0L);
292*03ec5856SFlorian Fainelli 
293*03ec5856SFlorian Fainelli 	rc32434_wdt_device.default_ticks = ticks;
294*03ec5856SFlorian Fainelli 
295*03ec5856SFlorian Fainelli 	rc32434_wdt_start();
296*03ec5856SFlorian Fainelli 
297*03ec5856SFlorian Fainelli 	printk(banner, timeout);
298*03ec5856SFlorian Fainelli 
299*03ec5856SFlorian Fainelli 	return 0;
300*03ec5856SFlorian Fainelli 
301*03ec5856SFlorian Fainelli unmap:
302*03ec5856SFlorian Fainelli 	iounmap(wdt_reg);
303*03ec5856SFlorian Fainelli 	return ret;
304*03ec5856SFlorian Fainelli }
305*03ec5856SFlorian Fainelli 
306*03ec5856SFlorian Fainelli static int rc32434_wdt_remove(struct platform_device *pdev)
307*03ec5856SFlorian Fainelli {
308*03ec5856SFlorian Fainelli 	if (rc32434_wdt_device.queue) {
309*03ec5856SFlorian Fainelli 		rc32434_wdt_device.queue = 0;
310*03ec5856SFlorian Fainelli 		wait_for_completion(&rc32434_wdt_device.stop);
311*03ec5856SFlorian Fainelli 	}
312*03ec5856SFlorian Fainelli 	misc_deregister(&rc32434_wdt_miscdev);
313*03ec5856SFlorian Fainelli 
314*03ec5856SFlorian Fainelli 	iounmap(wdt_reg);
315*03ec5856SFlorian Fainelli 
316*03ec5856SFlorian Fainelli 	return 0;
317*03ec5856SFlorian Fainelli }
318*03ec5856SFlorian Fainelli 
319*03ec5856SFlorian Fainelli static struct platform_driver rc32434_wdt = {
320*03ec5856SFlorian Fainelli 	.probe	= rc32434_wdt_probe,
321*03ec5856SFlorian Fainelli 	.remove = rc32434_wdt_remove,
322*03ec5856SFlorian Fainelli 	.driver = {
323*03ec5856SFlorian Fainelli 		.name = "rc32434_wdt",
324*03ec5856SFlorian Fainelli 	}
325*03ec5856SFlorian Fainelli };
326*03ec5856SFlorian Fainelli 
327*03ec5856SFlorian Fainelli static int __init rc32434_wdt_init(void)
328*03ec5856SFlorian Fainelli {
329*03ec5856SFlorian Fainelli 	return platform_driver_register(&rc32434_wdt);
330*03ec5856SFlorian Fainelli }
331*03ec5856SFlorian Fainelli 
332*03ec5856SFlorian Fainelli static void __exit rc32434_wdt_exit(void)
333*03ec5856SFlorian Fainelli {
334*03ec5856SFlorian Fainelli 	platform_driver_unregister(&rc32434_wdt);
335*03ec5856SFlorian Fainelli }
336*03ec5856SFlorian Fainelli 
337*03ec5856SFlorian Fainelli module_init(rc32434_wdt_init);
338*03ec5856SFlorian Fainelli module_exit(rc32434_wdt_exit);
339*03ec5856SFlorian Fainelli 
340*03ec5856SFlorian Fainelli MODULE_AUTHOR("Ondrej Zajicek <santiago@crfreenet.org>,"
341*03ec5856SFlorian Fainelli 		"Florian Fainelli <florian@openwrt.org>");
342*03ec5856SFlorian Fainelli MODULE_DESCRIPTION("Driver for the IDT RC32434 SoC watchdog");
343*03ec5856SFlorian Fainelli MODULE_LICENSE("GPL");
344*03ec5856SFlorian Fainelli MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
345