| Linux kernel & device driver programming |
| [ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] |
1 /* 1
2 * RDC321x watchdog driver
3 *
4 * Copyright (C) 2007 Florian Fainelli <floria
5 *
6 * This driver is highly inspired from the cpu
7 *
8 * This program is free software; you can redi
9 * it under the terms of the GNU General Publi
10 * the Free Software Foundation; either versio
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope tha
14 * but WITHOUT ANY WARRANTY; without even the
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * GNU General Public License for more details
17 *
18 * You should have received a copy of the GNU
19 * along with this program; if not, write to t
20 * Foundation, Inc., 675 Mass Ave, Cambridge,
21 *
22 */
23
24 #include <linux/module.h>
25 #include <linux/moduleparam.h>
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/miscdevice.h>
29 #include <linux/fs.h>
30 #include <linux/init.h>
31 #include <linux/ioport.h>
32 #include <linux/timer.h>
33 #include <linux/completion.h>
34 #include <linux/jiffies.h>
35 #include <linux/platform_device.h>
36 #include <linux/watchdog.h>
37 #include <linux/io.h>
38 #include <linux/uaccess.h>
39
40 #include <asm/mach-rdc321x/rdc321x_defs.h>
41
42 #define RDC_WDT_MASK 0x80000000 /* Mask */
43 #define RDC_WDT_EN 0x00800000 /* Enable b
44 #define RDC_WDT_WTI 0x00200000 /* Generate
45 #define RDC_WDT_RST 0x00100000 /* Reset bi
46 #define RDC_WDT_WIF 0x00040000 /* WDT IRQ
47 #define RDC_WDT_IRT 0x00000100 /* IRQ Rout
48 #define RDC_WDT_CNT 0x00000001 /* WDT coun
49
50 #define RDC_CLS_TMR 0x80003844 /* Clear ti
51
52 #define RDC_WDT_INTERVAL (HZ/10+1)
53
54 int nowayout = WATCHDOG_NOWAYOUT;
55 module_param(nowayout, int, 0);
56 MODULE_PARM_DESC(nowayout, "Watchdog cannot be
57
58 static int ticks = 1000;
59
60 /* some device data */
61
62 static struct {
63 struct completion stop;
64 volatile int running;
65 struct timer_list timer;
66 volatile int queue;
67 int default_ticks;
68 unsigned long inuse;
69 } rdc321x_wdt_device;
70
71 /* generic helper functions */
72
73 static void rdc321x_wdt_trigger(unsigned long
74 {
75 if (rdc321x_wdt_device.running)
76 ticks--;
77
78 /* keep watchdog alive */
79 outl(RDC_WDT_EN|inl(RDC3210_CFGREG_DAT
80
81 /* requeue?? */
82 if (rdc321x_wdt_device.queue && ticks)
83 mod_timer(&rdc321x_wdt_device.
84 jiffies + RDC_
85 else {
86 /* ticks doesn't matter anyway
87 complete(&rdc321x_wdt_device.s
88 }
89
90 }
91
92 static void rdc321x_wdt_reset(void)
93 {
94 ticks = rdc321x_wdt_device.default_tic
95 }
96
97 static void rdc321x_wdt_start(void)
98 {
99 if (!rdc321x_wdt_device.queue) {
100 rdc321x_wdt_device.queue = 1;
101
102 /* Clear the timer */
103 outl(RDC_CLS_TMR, RDC3210_CFGR
104
105 /* Enable watchdog and set the
106 outl(RDC_WDT_EN|RDC_WDT_CNT, R
107
108 mod_timer(&rdc321x_wdt_device.
109 jiffies + RDC_
110 }
111
112 /* if process dies, counter is not dec
113 rdc321x_wdt_device.running++;
114 }
115
116 static int rdc321x_wdt_stop(void)
117 {
118 if (rdc321x_wdt_device.running)
119 rdc321x_wdt_device.running = 0
120
121 ticks = rdc321x_wdt_device.default_tic
122
123 return -EIO;
124 }
125
126 /* filesystem operations */
127
128 static int rdc321x_wdt_open(struct inode *inod
129 {
130 if (test_and_set_bit(0, &rdc321x_wdt_d
131 return -EBUSY;
132
133 return nonseekable_open(inode, file);
134 }
135
136 static int rdc321x_wdt_release(struct inode *i
137 {
138 clear_bit(0, &rdc321x_wdt_device.inuse
139 return 0;
140 }
141
142 static int rdc321x_wdt_ioctl(struct inode *ino
143 unsigned int c
144 {
145 void __user *argp = (void __user *)arg
146 unsigned int value;
147 static struct watchdog_info ident = {
148 .options = WDIOF_CARDRESET,
149 .identity = "RDC321x WDT",
150 };
151
152 switch (cmd) {
153 case WDIOC_KEEPALIVE:
154 rdc321x_wdt_reset();
155 break;
156 case WDIOC_GETSTATUS:
157 /* Read the value from the DAT
158 value = inl(RDC3210_CFGREG_DAT
159 if (copy_to_user(argp, &value,
160 return -EFAULT;
161 break;
162 case WDIOC_GETSUPPORT:
163 if (copy_to_user(argp, &ident,
164 return -EFAULT;
165 break;
166 case WDIOC_SETOPTIONS:
167 if (copy_from_user(&value, arg
168 return -EFAULT;
169 switch (value) {
170 case WDIOS_ENABLECARD:
171 rdc321x_wdt_start();
172 break;
173 case WDIOS_DISABLECARD:
174 return rdc321x_wdt_sto
175 default:
176 return -EINVAL;
177 }
178 break;
179 default:
180 return -ENOTTY;
181 }
182 return 0;
183 }
184
185 static ssize_t rdc321x_wdt_write(struct file *
186 size_t count,
187 {
188 if (!count)
189 return -EIO;
190
191 rdc321x_wdt_reset();
192
193 return count;
194 }
195
196 static const struct file_operations rdc321x_wd
197 .owner = THIS_MODULE,
198 .llseek = no_llseek,
199 .ioctl = rdc321x_wdt_ioctl,
200 .open = rdc321x_wdt_open,
201 .write = rdc321x_wdt_write,
202 .release = rdc321x_wdt_release,
203 };
204
205 static struct miscdevice rdc321x_wdt_misc = {
206 .minor = WATCHDOG_MINOR,
207 .name = "watchdog",
208 .fops = &rdc321x_wdt_fops,
209 };
210
211 static int __devinit rdc321x_wdt_probe(struct
212 {
213 int err;
214
215 err = misc_register(&rdc321x_wdt_misc)
216 if (err < 0) {
217 printk(KERN_ERR PFX "watchdog
218 return err;
219 }
220
221 /* Reset the watchdog */
222 outl(RDC_WDT_RST, RDC3210_CFGREG_DATA)
223
224 init_completion(&rdc321x_wdt_device.st
225 rdc321x_wdt_device.queue = 0;
226
227 clear_bit(0, &rdc321x_wdt_device.inuse
228
229 setup_timer(&rdc321x_wdt_device.timer,
230
231 rdc321x_wdt_device.default_ticks = tic
232
233 printk(KERN_INFO PFX "watchdog init su
234
235 return 0;
236 }
237
238 static int rdc321x_wdt_remove(struct platform_
239 {
240 if (rdc321x_wdt_device.queue) {
241 rdc321x_wdt_device.queue = 0;
242 wait_for_completion(&rdc321x_w
243 }
244
245 misc_deregister(&rdc321x_wdt_misc);
246
247 return 0;
248 }
249
250 static struct platform_driver rdc321x_wdt_driv
251 .probe = rdc321x_wdt_probe,
252 .remove = rdc321x_wdt_remove,
253 .driver = {
254 .owner = THIS_MODULE,
255 .name = "rdc321x-wdt",
256 },
257 };
258
259 static int __init rdc321x_wdt_init(void)
260 {
261 return platform_driver_register(&rdc32
262 }
263
264 static void __exit rdc321x_wdt_exit(void)
265 {
266 platform_driver_unregister(&rdc321x_wd
267 }
268
269 module_init(rdc321x_wdt_init);
270 module_exit(rdc321x_wdt_exit);
271
272 MODULE_AUTHOR("Florian Fainelli <florian@openw
273 MODULE_DESCRIPTION("RDC321x watchdog driver");
274 MODULE_LICENSE("GPL");
275 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
276
| This page was automatically generated by the LXR engine. |