1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/miscdevice.h>
20#include <linux/notifier.h>
21#include <linux/watchdog.h>
22
23#include <asm/reg_booke.h>
24#include <asm/uaccess.h>
25#include <asm/system.h>
26
27
28
29
30
31
32
33
34
35#ifdef CONFIG_FSL_BOOKE
36#define WDT_PERIOD_DEFAULT 63
37#else
38#define WDT_PERIOD_DEFAULT 4
39#endif
40
41u32 booke_wdt_enabled = 0;
42u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
43
44#ifdef CONFIG_FSL_BOOKE
45#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15))
46#else
47#define WDTP(x) (TCR_WP(x))
48#endif
49
50
51
52
53static __inline__ void booke_wdt_enable(void)
54{
55 u32 val;
56
57 val = mfspr(SPRN_TCR);
58 val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
59
60 mtspr(SPRN_TCR, val);
61}
62
63
64
65
66static __inline__ void booke_wdt_ping(void)
67{
68 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
69}
70
71
72
73
74static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
75 size_t count, loff_t *ppos)
76{
77 booke_wdt_ping();
78 return count;
79}
80
81static struct watchdog_info ident = {
82 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
83 .firmware_version = 0,
84 .identity = "PowerPC Book-E Watchdog",
85};
86
87
88
89
90static int booke_wdt_ioctl (struct inode *inode, struct file *file,
91 unsigned int cmd, unsigned long arg)
92{
93 u32 tmp = 0;
94 u32 __user *p = (u32 __user *)arg;
95
96 switch (cmd) {
97 case WDIOC_GETSUPPORT:
98 if (copy_to_user ((struct watchdog_info __user *) arg, &ident,
99 sizeof(struct watchdog_info)))
100 return -EFAULT;
101 case WDIOC_GETSTATUS:
102 return put_user(ident.options, p);
103 case WDIOC_GETBOOTSTATUS:
104
105 tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
106
107 return (tmp ? 1 : 0);
108 case WDIOC_KEEPALIVE:
109 booke_wdt_ping();
110 return 0;
111 case WDIOC_SETTIMEOUT:
112 if (get_user(booke_wdt_period, p))
113 return -EFAULT;
114 mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
115 return 0;
116 case WDIOC_GETTIMEOUT:
117 return put_user(booke_wdt_period, p);
118 case WDIOC_SETOPTIONS:
119 if (get_user(tmp, p))
120 return -EINVAL;
121 if (tmp == WDIOS_ENABLECARD) {
122 booke_wdt_ping();
123 break;
124 } else
125 return -EINVAL;
126 return 0;
127 default:
128 return -ENOTTY;
129 }
130
131 return 0;
132}
133
134
135
136static int booke_wdt_open (struct inode *inode, struct file *file)
137{
138 if (booke_wdt_enabled == 0) {
139 booke_wdt_enabled = 1;
140 booke_wdt_enable();
141 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
142 booke_wdt_period);
143 }
144
145 return 0;
146}
147
148static const struct file_operations booke_wdt_fops = {
149 .owner = THIS_MODULE,
150 .llseek = no_llseek,
151 .write = booke_wdt_write,
152 .ioctl = booke_wdt_ioctl,
153 .open = booke_wdt_open,
154};
155
156static struct miscdevice booke_wdt_miscdev = {
157 .minor = WATCHDOG_MINOR,
158 .name = "watchdog",
159 .fops = &booke_wdt_fops,
160};
161
162static void __exit booke_wdt_exit(void)
163{
164 misc_deregister(&booke_wdt_miscdev);
165}
166
167
168
169
170static int __init booke_wdt_init(void)
171{
172 int ret = 0;
173
174 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
175 ident.firmware_version = cur_cpu_spec->pvr_value;
176
177 ret = misc_register(&booke_wdt_miscdev);
178 if (ret) {
179 printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
180 WATCHDOG_MINOR, ret);
181 return ret;
182 }
183
184 if (booke_wdt_enabled == 1) {
185 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
186 booke_wdt_period);
187 booke_wdt_enable();
188 }
189
190 return ret;
191}
192device_initcall(booke_wdt_init);
193