Blame view

drivers/watchdog/riowd.c 5.69 KB
957183f32   David S. Miller   riowatchdog: Move...
1
  /* riowd.c - driver for hw watchdog inside Super I/O of RIO
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   *
e42311d75   David S. Miller   riowatchdog: Conv...
3
   * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/fs.h>
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/miscdevice.h>
e42311d75   David S. Miller   riowatchdog: Conv...
13
14
15
  #include <linux/watchdog.h>
  #include <linux/of.h>
  #include <linux/of_device.h>
278aefc51   Wim Van Sebroeck   [WATCHDOG] Fix io...
16
17
  #include <linux/io.h>
  #include <linux/uaccess.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  
  /* RIO uses the NatSemi Super I/O power management logical device
   * as its' watchdog.
   *
   * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
   * Controller) of the machine.  The BBC can only be configured to
   * trigger a power-on reset when the signal is asserted.  The BBC
   * can be configured to ignore the signal entirely as well.
   *
   * The only Super I/O device register we care about is at index
   * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
   * If set to zero, this disables the watchdog.  When set, the system
   * must periodically (before watchdog expires) clear (set to zero) and
   * re-set the watchdog else it will trigger.
   *
   * There are two other indexed watchdog registers inside this Super I/O
   * logical device, but they are unused.  The first, at index 0x06 is
   * the watchdog control and can be used to make the watchdog timer re-set
   * when the PS/2 mouse or serial lines show activity.  The second, at
   * index 0x07 is merely a sampling of the line from the watchdog to the
   * BBC.
   *
   * The watchdog device generates no interrupts.
   */
e42311d75   David S. Miller   riowatchdog: Conv...
44
  MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
  MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
  MODULE_SUPPORTED_DEVICE("watchdog");
  MODULE_LICENSE("GPL");
e25ecd08c   David S. Miller   riowd: Distinguis...
48
49
  #define DRIVER_NAME	"riowd"
  #define PFX		DRIVER_NAME ": "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

e42311d75   David S. Miller   riowatchdog: Conv...
51
52
53
54
55
56
  struct riowd {
  	void __iomem		*regs;
  	spinlock_t		lock;
  };
  
  static struct riowd *riowd_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
  #define WDTO_INDEX	0x05
  
  static int riowd_timeout = 1;		/* in minutes */
  module_param(riowd_timeout, int, 0);
  MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
e42311d75   David S. Miller   riowatchdog: Conv...
63
  static void riowd_writereg(struct riowd *p, u8 val, int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  {
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

e42311d75   David S. Miller   riowatchdog: Conv...
67
68
69
70
  	spin_lock_irqsave(&p->lock, flags);
  	writeb(index, p->regs + 0);
  	writeb(val, p->regs + 1);
  	spin_unlock_irqrestore(&p->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
79
80
81
82
  }
  
  static int riowd_open(struct inode *inode, struct file *filp)
  {
  	nonseekable_open(inode, filp);
  	return 0;
  }
  
  static int riowd_release(struct inode *inode, struct file *filp)
  {
  	return 0;
  }
9626dd75c   Wim Van Sebroeck   [WATCHDOG] cpwd.c...
83
  static long riowd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
42747d712   Wim Van Sebroeck   [WATCHDOG] watchd...
85
  	static const struct watchdog_info info = {
e42311d75   David S. Miller   riowatchdog: Conv...
86
87
  		.options		= WDIOF_SETTIMEOUT,
  		.firmware_version	= 1,
e25ecd08c   David S. Miller   riowd: Distinguis...
88
  		.identity		= DRIVER_NAME,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  	};
  	void __user *argp = (void __user *)arg;
e42311d75   David S. Miller   riowatchdog: Conv...
91
  	struct riowd *p = riowd_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  	unsigned int options;
  	int new_margin;
  
  	switch (cmd) {
  	case WDIOC_GETSUPPORT:
  		if (copy_to_user(argp, &info, sizeof(info)))
  			return -EFAULT;
  		break;
  
  	case WDIOC_GETSTATUS:
  	case WDIOC_GETBOOTSTATUS:
  		if (put_user(0, (int __user *)argp))
  			return -EFAULT;
  		break;
  
  	case WDIOC_KEEPALIVE:
e42311d75   David S. Miller   riowatchdog: Conv...
108
  		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
113
114
115
  		break;
  
  	case WDIOC_SETOPTIONS:
  		if (copy_from_user(&options, argp, sizeof(options)))
  			return -EFAULT;
  
  		if (options & WDIOS_DISABLECARD)
e42311d75   David S. Miller   riowatchdog: Conv...
116
  			riowd_writereg(p, 0, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  		else if (options & WDIOS_ENABLECARD)
e42311d75   David S. Miller   riowatchdog: Conv...
118
  			riowd_writereg(p, riowd_timeout, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
126
127
  		else
  			return -EINVAL;
  
  		break;
  
  	case WDIOC_SETTIMEOUT:
  		if (get_user(new_margin, (int __user *)argp))
  			return -EFAULT;
  		if ((new_margin < 60) || (new_margin > (255 * 60)))
e42311d75   David S. Miller   riowatchdog: Conv...
128
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  		riowd_timeout = (new_margin + 59) / 60;
e42311d75   David S. Miller   riowatchdog: Conv...
130
  		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
138
139
140
141
  		/* Fall */
  
  	case WDIOC_GETTIMEOUT:
  		return put_user(riowd_timeout * 60, (int __user *)argp);
  
  	default:
  		return -EINVAL;
  	};
  
  	return 0;
  }
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
142
143
  static ssize_t riowd_write(struct file *file, const char __user *buf,
  						size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  {
e42311d75   David S. Miller   riowatchdog: Conv...
145
  	struct riowd *p = riowd_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	if (count) {
e42311d75   David S. Miller   riowatchdog: Conv...
147
  		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
152
  		return 1;
  	}
  
  	return 0;
  }
00977a59b   Arjan van de Ven   [PATCH] mark stru...
153
  static const struct file_operations riowd_fops = {
9626dd75c   Wim Van Sebroeck   [WATCHDOG] cpwd.c...
154
155
156
157
158
159
  	.owner =		THIS_MODULE,
  	.llseek =		no_llseek,
  	.unlocked_ioctl =	riowd_ioctl,
  	.open =			riowd_open,
  	.write =		riowd_write,
  	.release =		riowd_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  };
e42311d75   David S. Miller   riowatchdog: Conv...
161
162
163
164
165
  static struct miscdevice riowd_miscdev = {
  	.minor	= WATCHDOG_MINOR,
  	.name	= "watchdog",
  	.fops	= &riowd_fops
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166

1c48a5c93   Grant Likely   dt: Eliminate of_...
167
  static int __devinit riowd_probe(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
e42311d75   David S. Miller   riowatchdog: Conv...
169
170
  	struct riowd *p;
  	int err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

e42311d75   David S. Miller   riowatchdog: Conv...
172
173
  	if (riowd_device)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174

e42311d75   David S. Miller   riowatchdog: Conv...
175
176
177
178
  	err = -ENOMEM;
  	p = kzalloc(sizeof(*p), GFP_KERNEL);
  	if (!p)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

e42311d75   David S. Miller   riowatchdog: Conv...
180
  	spin_lock_init(&p->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

e25ecd08c   David S. Miller   riowd: Distinguis...
182
  	p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
e42311d75   David S. Miller   riowatchdog: Conv...
183
184
185
186
  	if (!p->regs) {
  		printk(KERN_ERR PFX "Cannot map registers.
  ");
  		goto out_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	}
462265bf4   Thomas Gleixner   watchdog: Remove ...
188
189
  	/* Make miscdev useable right away */
  	riowd_device = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190

e42311d75   David S. Miller   riowatchdog: Conv...
191
192
193
194
195
  	err = misc_register(&riowd_miscdev);
  	if (err) {
  		printk(KERN_ERR PFX "Cannot register watchdog misc device.
  ");
  		goto out_iounmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  	}
e42311d75   David S. Miller   riowatchdog: Conv...
197
198
199
  	printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
  	       "regs at %p
  ", riowd_timeout, p->regs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200

e42311d75   David S. Miller   riowatchdog: Conv...
201
  	dev_set_drvdata(&op->dev, p);
03717e3d1   Thomas Gleixner   watchdog: Fix rio...
202
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

e42311d75   David S. Miller   riowatchdog: Conv...
204
  out_iounmap:
462265bf4   Thomas Gleixner   watchdog: Remove ...
205
  	riowd_device = NULL;
e42311d75   David S. Miller   riowatchdog: Conv...
206
  	of_iounmap(&op->resource[0], p->regs, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

e42311d75   David S. Miller   riowatchdog: Conv...
208
209
  out_free:
  	kfree(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210

e42311d75   David S. Miller   riowatchdog: Conv...
211
212
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  }
2dc115813   Grant Likely   of/device: Replac...
214
  static int __devexit riowd_remove(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  {
e42311d75   David S. Miller   riowatchdog: Conv...
216
  	struct riowd *p = dev_get_drvdata(&op->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	misc_deregister(&riowd_miscdev);
e42311d75   David S. Miller   riowatchdog: Conv...
218
219
220
221
222
  	of_iounmap(&op->resource[0], p->regs, 2);
  	kfree(p);
  
  	return 0;
  }
fd098316e   David S. Miller   sparc: Annotate o...
223
  static const struct of_device_id riowd_match[] = {
e42311d75   David S. Miller   riowatchdog: Conv...
224
225
226
227
228
229
  	{
  		.name = "pmc",
  	},
  	{},
  };
  MODULE_DEVICE_TABLE(of, riowd_match);
1c48a5c93   Grant Likely   dt: Eliminate of_...
230
  static struct platform_driver riowd_driver = {
4018294b5   Grant Likely   of: Remove duplic...
231
232
233
234
235
  	.driver = {
  		.name = DRIVER_NAME,
  		.owner = THIS_MODULE,
  		.of_match_table = riowd_match,
  	},
e42311d75   David S. Miller   riowatchdog: Conv...
236
237
238
  	.probe		= riowd_probe,
  	.remove		= __devexit_p(riowd_remove),
  };
b8ec61189   Axel Lin   watchdog: convert...
239
  module_platform_driver(riowd_driver);