watchdog: Use pr_<fmt> and pr_<level>
[deliverable/linux.git] / drivers / watchdog / wm8350_wdt.c
1 /*
2 * Watchdog driver for the wm8350
3 *
4 * Copyright (C) 2007, 2008 Wolfson Microelectronics <linux@wolfsonmicro.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation
9 */
10
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/types.h>
16 #include <linux/kernel.h>
17 #include <linux/fs.h>
18 #include <linux/miscdevice.h>
19 #include <linux/platform_device.h>
20 #include <linux/watchdog.h>
21 #include <linux/uaccess.h>
22 #include <linux/mfd/wm8350/core.h>
23
24 static int nowayout = WATCHDOG_NOWAYOUT;
25 module_param(nowayout, int, 0);
26 MODULE_PARM_DESC(nowayout,
27 "Watchdog cannot be stopped once started (default="
28 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
29
30 static unsigned long wm8350_wdt_users;
31 static struct miscdevice wm8350_wdt_miscdev;
32 static int wm8350_wdt_expect_close;
33 static DEFINE_MUTEX(wdt_mutex);
34
35 static struct {
36 int time; /* Seconds */
37 u16 val; /* To be set in WM8350_SYSTEM_CONTROL_2 */
38 } wm8350_wdt_cfgs[] = {
39 { 1, 0x02 },
40 { 2, 0x04 },
41 { 4, 0x05 },
42 };
43
44 static struct wm8350 *get_wm8350(void)
45 {
46 return dev_get_drvdata(wm8350_wdt_miscdev.parent);
47 }
48
49 static int wm8350_wdt_set_timeout(struct wm8350 *wm8350, u16 value)
50 {
51 int ret;
52 u16 reg;
53
54 mutex_lock(&wdt_mutex);
55 wm8350_reg_unlock(wm8350);
56
57 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
58 reg &= ~WM8350_WDOG_TO_MASK;
59 reg |= value;
60 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
61
62 wm8350_reg_lock(wm8350);
63 mutex_unlock(&wdt_mutex);
64
65 return ret;
66 }
67
68 static int wm8350_wdt_start(struct wm8350 *wm8350)
69 {
70 int ret;
71 u16 reg;
72
73 mutex_lock(&wdt_mutex);
74 wm8350_reg_unlock(wm8350);
75
76 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
77 reg &= ~WM8350_WDOG_MODE_MASK;
78 reg |= 0x20;
79 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
80
81 wm8350_reg_lock(wm8350);
82 mutex_unlock(&wdt_mutex);
83
84 return ret;
85 }
86
87 static int wm8350_wdt_stop(struct wm8350 *wm8350)
88 {
89 int ret;
90 u16 reg;
91
92 mutex_lock(&wdt_mutex);
93 wm8350_reg_unlock(wm8350);
94
95 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
96 reg &= ~WM8350_WDOG_MODE_MASK;
97 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
98
99 wm8350_reg_lock(wm8350);
100 mutex_unlock(&wdt_mutex);
101
102 return ret;
103 }
104
105 static int wm8350_wdt_kick(struct wm8350 *wm8350)
106 {
107 int ret;
108 u16 reg;
109
110 mutex_lock(&wdt_mutex);
111
112 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
113 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
114
115 mutex_unlock(&wdt_mutex);
116
117 return ret;
118 }
119
120 static int wm8350_wdt_open(struct inode *inode, struct file *file)
121 {
122 struct wm8350 *wm8350 = get_wm8350();
123 int ret;
124
125 if (!wm8350)
126 return -ENODEV;
127
128 if (test_and_set_bit(0, &wm8350_wdt_users))
129 return -EBUSY;
130
131 ret = wm8350_wdt_start(wm8350);
132 if (ret != 0)
133 return ret;
134
135 return nonseekable_open(inode, file);
136 }
137
138 static int wm8350_wdt_release(struct inode *inode, struct file *file)
139 {
140 struct wm8350 *wm8350 = get_wm8350();
141
142 if (wm8350_wdt_expect_close)
143 wm8350_wdt_stop(wm8350);
144 else {
145 dev_warn(wm8350->dev, "Watchdog device closed uncleanly\n");
146 wm8350_wdt_kick(wm8350);
147 }
148
149 clear_bit(0, &wm8350_wdt_users);
150
151 return 0;
152 }
153
154 static ssize_t wm8350_wdt_write(struct file *file,
155 const char __user *data, size_t count,
156 loff_t *ppos)
157 {
158 struct wm8350 *wm8350 = get_wm8350();
159 size_t i;
160
161 if (count) {
162 wm8350_wdt_kick(wm8350);
163
164 if (!nowayout) {
165 /* In case it was set long ago */
166 wm8350_wdt_expect_close = 0;
167
168 /* scan to see whether or not we got the magic
169 character */
170 for (i = 0; i != count; i++) {
171 char c;
172 if (get_user(c, data + i))
173 return -EFAULT;
174 if (c == 'V')
175 wm8350_wdt_expect_close = 42;
176 }
177 }
178 }
179 return count;
180 }
181
182 static const struct watchdog_info ident = {
183 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
184 .identity = "WM8350 Watchdog",
185 };
186
187 static long wm8350_wdt_ioctl(struct file *file, unsigned int cmd,
188 unsigned long arg)
189 {
190 struct wm8350 *wm8350 = get_wm8350();
191 int ret = -ENOTTY, time, i;
192 void __user *argp = (void __user *)arg;
193 int __user *p = argp;
194 u16 reg;
195
196 switch (cmd) {
197 case WDIOC_GETSUPPORT:
198 ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
199 break;
200
201 case WDIOC_GETSTATUS:
202 case WDIOC_GETBOOTSTATUS:
203 ret = put_user(0, p);
204 break;
205
206 case WDIOC_SETOPTIONS:
207 {
208 int options;
209
210 if (get_user(options, p))
211 return -EFAULT;
212
213 ret = -EINVAL;
214
215 /* Setting both simultaneously means at least one must fail */
216 if (options == WDIOS_DISABLECARD)
217 ret = wm8350_wdt_stop(wm8350);
218
219 if (options == WDIOS_ENABLECARD)
220 ret = wm8350_wdt_start(wm8350);
221 break;
222 }
223
224 case WDIOC_KEEPALIVE:
225 ret = wm8350_wdt_kick(wm8350);
226 break;
227
228 case WDIOC_SETTIMEOUT:
229 ret = get_user(time, p);
230 if (ret)
231 break;
232
233 if (time == 0) {
234 if (nowayout)
235 ret = -EINVAL;
236 else
237 wm8350_wdt_stop(wm8350);
238 break;
239 }
240
241 for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
242 if (wm8350_wdt_cfgs[i].time == time)
243 break;
244 if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
245 ret = -EINVAL;
246 else
247 ret = wm8350_wdt_set_timeout(wm8350,
248 wm8350_wdt_cfgs[i].val);
249 break;
250
251 case WDIOC_GETTIMEOUT:
252 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
253 reg &= WM8350_WDOG_TO_MASK;
254 for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
255 if (wm8350_wdt_cfgs[i].val == reg)
256 break;
257 if (i == ARRAY_SIZE(wm8350_wdt_cfgs)) {
258 dev_warn(wm8350->dev,
259 "Unknown watchdog configuration: %x\n", reg);
260 ret = -EINVAL;
261 } else
262 ret = put_user(wm8350_wdt_cfgs[i].time, p);
263
264 }
265
266 return ret;
267 }
268
269 static const struct file_operations wm8350_wdt_fops = {
270 .owner = THIS_MODULE,
271 .llseek = no_llseek,
272 .write = wm8350_wdt_write,
273 .unlocked_ioctl = wm8350_wdt_ioctl,
274 .open = wm8350_wdt_open,
275 .release = wm8350_wdt_release,
276 };
277
278 static struct miscdevice wm8350_wdt_miscdev = {
279 .minor = WATCHDOG_MINOR,
280 .name = "watchdog",
281 .fops = &wm8350_wdt_fops,
282 };
283
284 static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
285 {
286 struct wm8350 *wm8350 = platform_get_drvdata(pdev);
287
288 if (!wm8350) {
289 pr_err("No driver data supplied\n");
290 return -ENODEV;
291 }
292
293 /* Default to 4s timeout */
294 wm8350_wdt_set_timeout(wm8350, 0x05);
295
296 wm8350_wdt_miscdev.parent = &pdev->dev;
297
298 return misc_register(&wm8350_wdt_miscdev);
299 }
300
301 static int __devexit wm8350_wdt_remove(struct platform_device *pdev)
302 {
303 misc_deregister(&wm8350_wdt_miscdev);
304
305 return 0;
306 }
307
308 static struct platform_driver wm8350_wdt_driver = {
309 .probe = wm8350_wdt_probe,
310 .remove = __devexit_p(wm8350_wdt_remove),
311 .driver = {
312 .name = "wm8350-wdt",
313 },
314 };
315
316 module_platform_driver(wm8350_wdt_driver);
317
318 MODULE_AUTHOR("Mark Brown");
319 MODULE_DESCRIPTION("WM8350 Watchdog");
320 MODULE_LICENSE("GPL");
321 MODULE_ALIAS("platform:wm8350-wdt");
This page took 0.057126 seconds and 5 git commands to generate.