aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sbus/char')
-rw-r--r--drivers/sbus/char/riowatchdog.c234
1 files changed, 99 insertions, 135 deletions
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c
index 88c0fc6395e1..b53af832a3af 100644
--- a/drivers/sbus/char/riowatchdog.c
+++ b/drivers/sbus/char/riowatchdog.c
@@ -1,7 +1,6 @@
1/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $ 1/* riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
2 * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
3 * 2 *
4 * Copyright (C) 2001 David S. Miller (davem@redhat.com) 3 * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
5 */ 4 */
6 5
7#include <linux/kernel.h> 6#include <linux/kernel.h>
@@ -12,14 +11,13 @@
12#include <linux/init.h> 11#include <linux/init.h>
13#include <linux/miscdevice.h> 12#include <linux/miscdevice.h>
14#include <linux/smp_lock.h> 13#include <linux/smp_lock.h>
14#include <linux/watchdog.h>
15#include <linux/of.h>
16#include <linux/of_device.h>
15 17
16#include <asm/io.h> 18#include <asm/io.h>
17#include <asm/ebus.h>
18#include <asm/bbc.h>
19#include <asm/oplib.h>
20#include <asm/uaccess.h> 19#include <asm/uaccess.h>
21 20
22#include <asm/watchdog.h>
23 21
24/* RIO uses the NatSemi Super I/O power management logical device 22/* RIO uses the NatSemi Super I/O power management logical device
25 * as its' watchdog. 23 * as its' watchdog.
@@ -45,74 +43,35 @@
45 * The watchdog device generates no interrupts. 43 * The watchdog device generates no interrupts.
46 */ 44 */
47 45
48MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 46MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
49MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO"); 47MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
50MODULE_SUPPORTED_DEVICE("watchdog"); 48MODULE_SUPPORTED_DEVICE("watchdog");
51MODULE_LICENSE("GPL"); 49MODULE_LICENSE("GPL");
52 50
53#define RIOWD_NAME "pmc" 51#define RIOWD_NAME "pmc"
54#define RIOWD_MINOR 215 52#define PFX RIOWD_NAME ": "
55 53
56static DEFINE_SPINLOCK(riowd_lock); 54struct riowd {
55 void __iomem *regs;
56 spinlock_t lock;
57};
58
59static struct riowd *riowd_device;
57 60
58static void __iomem *bbc_regs;
59static void __iomem *riowd_regs;
60#define WDTO_INDEX 0x05 61#define WDTO_INDEX 0x05
61 62
62static int riowd_timeout = 1; /* in minutes */ 63static int riowd_timeout = 1; /* in minutes */
63module_param(riowd_timeout, int, 0); 64module_param(riowd_timeout, int, 0);
64MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); 65MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
65 66
66#if 0 /* Currently unused. */ 67static void riowd_writereg(struct riowd *p, u8 val, int index)
67static u8 riowd_readreg(int index)
68{ 68{
69 unsigned long flags; 69 unsigned long flags;
70 u8 ret;
71 70
72 spin_lock_irqsave(&riowd_lock, flags); 71 spin_lock_irqsave(&p->lock, flags);
73 writeb(index, riowd_regs + 0); 72 writeb(index, p->regs + 0);
74 ret = readb(riowd_regs + 1); 73 writeb(val, p->regs + 1);
75 spin_unlock_irqrestore(&riowd_lock, flags); 74 spin_unlock_irqrestore(&p->lock, flags);
76
77 return ret;
78}
79#endif
80
81static void riowd_writereg(u8 val, int index)
82{
83 unsigned long flags;
84
85 spin_lock_irqsave(&riowd_lock, flags);
86 writeb(index, riowd_regs + 0);
87 writeb(val, riowd_regs + 1);
88 spin_unlock_irqrestore(&riowd_lock, flags);
89}
90
91static void riowd_pingtimer(void)
92{
93 riowd_writereg(riowd_timeout, WDTO_INDEX);
94}
95
96static void riowd_stoptimer(void)
97{
98 u8 val;
99
100 riowd_writereg(0, WDTO_INDEX);
101
102 val = readb(bbc_regs + BBC_WDACTION);
103 val &= ~BBC_WDACTION_RST;
104 writeb(val, bbc_regs + BBC_WDACTION);
105}
106
107static void riowd_starttimer(void)
108{
109 u8 val;
110
111 riowd_writereg(riowd_timeout, WDTO_INDEX);
112
113 val = readb(bbc_regs + BBC_WDACTION);
114 val |= BBC_WDACTION_RST;
115 writeb(val, bbc_regs + BBC_WDACTION);
116} 75}
117 76
118static int riowd_open(struct inode *inode, struct file *filp) 77static int riowd_open(struct inode *inode, struct file *filp)
@@ -131,9 +90,12 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
131 unsigned int cmd, unsigned long arg) 90 unsigned int cmd, unsigned long arg)
132{ 91{
133 static struct watchdog_info info = { 92 static struct watchdog_info info = {
134 WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" 93 .options = WDIOF_SETTIMEOUT,
94 .firmware_version = 1,
95 .identity = "riowd",
135 }; 96 };
136 void __user *argp = (void __user *)arg; 97 void __user *argp = (void __user *)arg;
98 struct riowd *p = riowd_device;
137 unsigned int options; 99 unsigned int options;
138 int new_margin; 100 int new_margin;
139 101
@@ -150,7 +112,7 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
150 break; 112 break;
151 113
152 case WDIOC_KEEPALIVE: 114 case WDIOC_KEEPALIVE:
153 riowd_pingtimer(); 115 riowd_writereg(p, riowd_timeout, WDTO_INDEX);
154 break; 116 break;
155 117
156 case WDIOC_SETOPTIONS: 118 case WDIOC_SETOPTIONS:
@@ -158,9 +120,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
158 return -EFAULT; 120 return -EFAULT;
159 121
160 if (options & WDIOS_DISABLECARD) 122 if (options & WDIOS_DISABLECARD)
161 riowd_stoptimer(); 123 riowd_writereg(p, 0, WDTO_INDEX);
162 else if (options & WDIOS_ENABLECARD) 124 else if (options & WDIOS_ENABLECARD)
163 riowd_starttimer(); 125 riowd_writereg(p, riowd_timeout, WDTO_INDEX);
164 else 126 else
165 return -EINVAL; 127 return -EINVAL;
166 128
@@ -170,9 +132,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
170 if (get_user(new_margin, (int __user *)argp)) 132 if (get_user(new_margin, (int __user *)argp))
171 return -EFAULT; 133 return -EFAULT;
172 if ((new_margin < 60) || (new_margin > (255 * 60))) 134 if ((new_margin < 60) || (new_margin > (255 * 60)))
173 return -EINVAL; 135 return -EINVAL;
174 riowd_timeout = (new_margin + 59) / 60; 136 riowd_timeout = (new_margin + 59) / 60;
175 riowd_pingtimer(); 137 riowd_writereg(p, riowd_timeout, WDTO_INDEX);
176 /* Fall */ 138 /* Fall */
177 139
178 case WDIOC_GETTIMEOUT: 140 case WDIOC_GETTIMEOUT:
@@ -187,8 +149,10 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
187 149
188static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 150static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
189{ 151{
152 struct riowd *p = riowd_device;
153
190 if (count) { 154 if (count) {
191 riowd_pingtimer(); 155 riowd_writereg(p, riowd_timeout, WDTO_INDEX);
192 return 1; 156 return 1;
193 } 157 }
194 158
@@ -197,99 +161,99 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou
197 161
198static const struct file_operations riowd_fops = { 162static const struct file_operations riowd_fops = {
199 .owner = THIS_MODULE, 163 .owner = THIS_MODULE,
164 .llseek = no_llseek,
200 .ioctl = riowd_ioctl, 165 .ioctl = riowd_ioctl,
201 .open = riowd_open, 166 .open = riowd_open,
202 .write = riowd_write, 167 .write = riowd_write,
203 .release = riowd_release, 168 .release = riowd_release,
204}; 169};
205 170
206static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops }; 171static struct miscdevice riowd_miscdev = {
172 .minor = WATCHDOG_MINOR,
173 .name = "watchdog",
174 .fops = &riowd_fops
175};
207 176
208static int __init riowd_bbc_init(void) 177static int __devinit riowd_probe(struct of_device *op,
178 const struct of_device_id *match)
209{ 179{
210 struct linux_ebus *ebus = NULL; 180 struct riowd *p;
211 struct linux_ebus_device *edev = NULL; 181 int err = -EINVAL;
212 u8 val;
213
214 for_each_ebus(ebus) {
215 for_each_ebusdev(edev, ebus) {
216 if (!strcmp(edev->ofdev.node->name, "bbc"))
217 goto found_bbc;
218 }
219 }
220 182
221found_bbc: 183 if (riowd_device)
222 if (!edev) 184 goto out;
223 return -ENODEV;
224 bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE);
225 if (!bbc_regs)
226 return -ENODEV;
227 185
228 /* Turn it off. */ 186 err = -ENOMEM;
229 val = readb(bbc_regs + BBC_WDACTION); 187 p = kzalloc(sizeof(*p), GFP_KERNEL);
230 val &= ~BBC_WDACTION_RST; 188 if (!p)
231 writeb(val, bbc_regs + BBC_WDACTION); 189 goto out;
232 190
233 return 0; 191 spin_lock_init(&p->lock);
234}
235 192
236static int __init riowd_init(void) 193 p->regs = of_ioremap(&op->resource[0], 0, 2, "riowd");
237{ 194 if (!p->regs) {
238 struct linux_ebus *ebus = NULL; 195 printk(KERN_ERR PFX "Cannot map registers.\n");
239 struct linux_ebus_device *edev = NULL; 196 goto out_free;
240
241 for_each_ebus(ebus) {
242 for_each_ebusdev(edev, ebus) {
243 if (!strcmp(edev->ofdev.node->name, RIOWD_NAME))
244 goto ebus_done;
245 }
246 } 197 }
247 198
248ebus_done: 199 err = misc_register(&riowd_miscdev);
249 if (!edev) 200 if (err) {
250 goto fail; 201 printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
251 202 goto out_iounmap;
252 riowd_regs = ioremap(edev->resource[0].start, 2);
253 if (riowd_regs == NULL) {
254 printk(KERN_ERR "pmc: Cannot map registers.\n");
255 return -ENODEV;
256 } 203 }
257 204
258 if (riowd_bbc_init()) { 205 printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
259 printk(KERN_ERR "pmc: Failure initializing BBC config.\n"); 206 "regs at %p\n", riowd_timeout, p->regs);
260 goto fail;
261 }
262 207
263 if (misc_register(&riowd_miscdev)) { 208 dev_set_drvdata(&op->dev, p);
264 printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n"); 209 riowd_device = p;
265 goto fail; 210 err = 0;
266 }
267 211
268 printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], " 212out_iounmap:
269 "regs at %p\n", riowd_timeout, riowd_regs); 213 of_iounmap(&op->resource[0], p->regs, 2);
270 214
271 return 0; 215out_free:
216 kfree(p);
272 217
273fail: 218out:
274 if (riowd_regs) { 219 return err;
275 iounmap(riowd_regs);
276 riowd_regs = NULL;
277 }
278 if (bbc_regs) {
279 iounmap(bbc_regs);
280 bbc_regs = NULL;
281 }
282 return -ENODEV;
283} 220}
284 221
285static void __exit riowd_cleanup(void) 222static int __devexit riowd_remove(struct of_device *op)
286{ 223{
224 struct riowd *p = dev_get_drvdata(&op->dev);
225
287 misc_deregister(&riowd_miscdev); 226 misc_deregister(&riowd_miscdev);
288 iounmap(riowd_regs); 227 of_iounmap(&op->resource[0], p->regs, 2);
289 riowd_regs = NULL; 228 kfree(p);
290 iounmap(bbc_regs); 229
291 bbc_regs = NULL; 230 return 0;
231}
232
233static struct of_device_id riowd_match[] = {
234 {
235 .name = "pmc",
236 },
237 {},
238};
239MODULE_DEVICE_TABLE(of, riowd_match);
240
241static struct of_platform_driver riowd_driver = {
242 .name = "riowd",
243 .match_table = riowd_match,
244 .probe = riowd_probe,
245 .remove = __devexit_p(riowd_remove),
246};
247
248static int __init riowd_init(void)
249{
250 return of_register_driver(&riowd_driver, &of_bus_type);
251}
252
253static void __exit riowd_exit(void)
254{
255 of_unregister_driver(&riowd_driver);
292} 256}
293 257
294module_init(riowd_init); 258module_init(riowd_init);
295module_exit(riowd_cleanup); 259module_exit(riowd_exit);