c6a90f07b22fdbfdce99c93284c01d86b926f400
[openwrt/svn-archive/archive.git] / target / linux / amazon-2.6 / files / drivers / char / amazon_wdt.c
1 /*
2 * Infineon AP DC COM Amazon WDT driver
3 * Copyright 2004 Wu Qi Ming <gokimi@msn.com>
4 * All rights reserved
5 */
6 #if defined(MODVERSIONS)
7 #include <linux/modversions.h>
8 #endif
9
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
15 #include <linux/string.h>
16 #include <linux/timer.h>
17 #include <linux/fs.h>
18 #include <linux/errno.h>
19 #include <linux/proc_fs.h>
20 #include <linux/stat.h>
21 #include <linux/tty.h>
22 #include <linux/selection.h>
23 #include <linux/kmod.h>
24 #include <linux/vmalloc.h>
25 #include <linux/kdev_t.h>
26 #include <linux/ioctl.h>
27 #include <asm/uaccess.h>
28 #include <asm/system.h>
29 #include <asm/amazon/amazon.h>
30 #include <asm/amazon/amazon_wdt.h>
31
32 #define AMAZON_WDT_EMSG(fmt, args...) printk( "%s: " fmt, __FUNCTION__ , ##args)
33
34 extern unsigned int amazon_get_fpi_hz(void);
35
36 /* forward declarations for _fops */
37 static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *offset);
38 static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *offset);
39 static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
40 static int wdt_open(struct inode *inode, struct file *file);
41 static int wdt_release(struct inode *inode, struct file *file);
42 static int wdt_proc_read(char *buf, char **start, off_t offset,int count, int *eof, void *data);
43
44
45 static struct file_operations wdt_fops = {
46 read:wdt_read,
47 write:wdt_write,
48 ioctl:wdt_ioctl,
49 open:wdt_open,
50 release:wdt_release,
51 };
52
53 /* data */
54 static struct wdt_dev *amazon_wdt_dev;
55 static struct proc_dir_entry* amazon_wdt_dir;
56 static int occupied=0;
57
58
59 /* Brief: enable WDT
60 * Parameter:
61 timeout: time interval for WDT
62 * Return:
63 0 OK
64 EINVAL
65 * Describes:
66 1. Password Access
67 2. Modify Access (change ENDINIT => 0)
68 3. Change WDT_CON1 (enable WDT)
69 4. Password Access again
70 5. Modify Access (change ENDINIT => 1)
71 */
72 int wdt_enable(int timeout)
73 {
74 u32 hard_psw,ffpi;
75 int reload_value, divider=0;
76
77 ffpi = amazon_get_fpi_hz();
78
79 divider = 1;
80 if((reload_value=65536-timeout*ffpi/256)<0){
81 divider = 0;
82 reload_value=65536-timeout*ffpi/16384;
83 }
84 if (reload_value < 0){
85 AMAZON_WDT_EMSG("timeout too large %d\n", timeout);
86 return -EINVAL;
87 }
88
89 AMAZON_WDT_EMSG("timeout:%d reload_value: %8x\n", timeout, reload_value);
90
91 hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;
92 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
93 wmb();
94
95 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(hard_psw&0xff00)+(reload_value<<16)+0xf2;
96 wmb();
97
98 AMAZON_WDT_REG32(AMAZON_WDT_CON1)=divider<<2;
99 wmb();
100
101 hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;
102 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
103
104 wmb();
105 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff00)+0xf3;
106 wmb();
107 return 0;
108 }
109
110 /* Brief: Disable/stop WDT
111 */
112 void wdt_disable(void)
113 {
114 u32 hard_psw=0;
115
116 hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;
117 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
118 wmb();
119
120 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff00)+0xf2;
121 wmb();
122
123 AMAZON_WDT_REG32(AMAZON_WDT_CON1)|=8;
124 wmb();
125
126 hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;
127 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
128 wmb();
129
130 AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff00)+0xf3;
131 wmb();
132
133 return;
134 }
135
136 static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
137 {
138 int result=0;
139 static int timeout=-1;
140
141 switch(cmd){
142 case AMAZON_WDT_IOC_START:
143 AMAZON_WDT_DMSG("enable watch dog timer!\n");
144 if ( copy_from_user((void*)&timeout, (void*)arg, sizeof (int)) ){
145 AMAZON_WDT_EMSG("invalid argument\n");
146 result=-EINVAL;
147 }else{
148 if ((result = wdt_enable(timeout)) < 0){
149 timeout = -1;
150 }
151 }
152 break;
153 case AMAZON_WDT_IOC_STOP:
154 AMAZON_WDT_DMSG("disable watch dog timer\n");
155 timeout = -1;
156 wdt_disable();
157
158 break;
159 case AMAZON_WDT_IOC_PING:
160 if (timeout <0 ){
161 result = -EIO;
162 }else{
163 result = wdt_enable(timeout);
164 }
165 }
166 return result;
167 }
168
169 static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *offset)
170 {
171 return 0;
172 }
173
174 static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *offset)
175 {
176 return count;
177 }
178
179 static int wdt_open(struct inode *inode, struct file *file)
180 {
181 AMAZON_WDT_DMSG("wdt_open\n");
182
183 if (occupied == 1) return -EBUSY;
184 occupied = 1;
185
186 return 0;
187 }
188
189 static int wdt_release(struct inode *inode, struct file *file)
190 {
191 AMAZON_WDT_DMSG("wdt_release\n");
192
193 occupied = 0;
194 return 0;
195 }
196
197
198 int wdt_register_proc_read(char *buf, char **start, off_t offset,
199 int count, int *eof, void *data)
200 {
201 int len=0;
202 printk("wdt_registers:\n");
203 len+=sprintf(buf+len,"NMISR: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_NMISR));
204 len+=sprintf(buf+len,"RST_REQ: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_RST_REQ));
205 len+=sprintf(buf+len,"RST_SR: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_RST_SR));
206 len+=sprintf(buf+len,"WDT_CON0: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_CON0));
207 len+=sprintf(buf+len,"WDT_CON1: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_CON1));
208 len+=sprintf(buf+len,"WDT_SR: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_SR));
209 *eof = 1;
210 return len;
211 }
212
213
214 int __init amazon_wdt_init_module(void)
215 {
216 int result=0;
217
218 amazon_wdt_dev = (wdt_dev*)kmalloc(sizeof(wdt_dev),GFP_KERNEL);
219 if (amazon_wdt_dev == NULL){
220 return -ENOMEM;
221 }
222 memset(amazon_wdt_dev,0,sizeof(wdt_dev));
223
224 amazon_wdt_dev->major=result;
225 strcpy(amazon_wdt_dev->name,"wdt");
226
227 result = register_chrdev(0,amazon_wdt_dev->name,&wdt_fops);
228 if (result < 0) {
229 AMAZON_WDT_EMSG("cannot register device\n");
230 kfree(amazon_wdt_dev);
231 return result;
232 }
233
234 amazon_wdt_dir=proc_mkdir("amazon_wdt",NULL);
235 create_proc_read_entry("wdt_register",
236 0,
237 amazon_wdt_dir,
238 wdt_register_proc_read,
239 NULL);
240
241 occupied=0;
242 return 0;
243 }
244
245 void amazon_wdt_cleanup_module(void)
246 {
247 unregister_chrdev(amazon_wdt_dev->major,amazon_wdt_dev->name);
248 kfree(amazon_wdt_dev);
249 remove_proc_entry("wdt_register",amazon_wdt_dir);
250 remove_proc_entry("amazon_wdt",NULL);
251 AMAZON_WDT_DMSG("unloaded\n");
252 return;
253 }
254
255 MODULE_LICENSE ("GPL");
256 MODULE_AUTHOR("Infineon IFAP DC COM");
257 MODULE_DESCRIPTION("AMAZON WDT driver");
258
259 module_init(amazon_wdt_init_module);
260 module_exit(amazon_wdt_cleanup_module);
261