aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-10-04 11:43:40 -0400
committerWim Van Sebroeck <wim@iguana.be>2011-11-05 16:28:59 -0400
commit00411ee9308e4b5f4b04caaa01685f955e259373 (patch)
tree5e614e61fdee4237ab0675651e8df52b24b9523f /drivers/watchdog
parent25dc46e3837cd01dc1742eefb73d064f6336850f (diff)
watchdog: Convert wm831x driver to watchdog core
Fairly large code churn but not much doing with that and the overall result is a definite win. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/wm831x_wdt.c318
2 files changed, 106 insertions, 213 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 40a36c50a5f4..6285867a9356 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -66,6 +66,7 @@ config SOFT_WATCHDOG
66config WM831X_WATCHDOG 66config WM831X_WATCHDOG
67 tristate "WM831x watchdog" 67 tristate "WM831x watchdog"
68 depends on MFD_WM831X 68 depends on MFD_WM831X
69 select WATCHDOG_CORE
69 help 70 help
70 Support for the watchdog in the WM831x AudioPlus PMICs. When 71 Support for the watchdog in the WM831x AudioPlus PMICs. When
71 the watchdog triggers the system will be reset. 72 the watchdog triggers the system will be reset.
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index 871caea4e1c6..7be38556aed0 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -12,8 +12,7 @@
12#include <linux/moduleparam.h> 12#include <linux/moduleparam.h>
13#include <linux/types.h> 13#include <linux/types.h>
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/fs.h> 15#include <linux/slab.h>
16#include <linux/miscdevice.h>
17#include <linux/platform_device.h> 16#include <linux/platform_device.h>
18#include <linux/watchdog.h> 17#include <linux/watchdog.h>
19#include <linux/uaccess.h> 18#include <linux/uaccess.h>
@@ -29,19 +28,19 @@ MODULE_PARM_DESC(nowayout,
29 "Watchdog cannot be stopped once started (default=" 28 "Watchdog cannot be stopped once started (default="
30 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 29 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
31 30
32static unsigned long wm831x_wdt_users; 31struct wm831x_wdt_drvdata {
33static struct miscdevice wm831x_wdt_miscdev; 32 struct watchdog_device wdt;
34static int wm831x_wdt_expect_close; 33 struct wm831x *wm831x;
35static DEFINE_MUTEX(wdt_mutex); 34 struct mutex lock;
36static struct wm831x *wm831x; 35 int update_gpio;
37static unsigned int update_gpio; 36 int update_state;
38static unsigned int update_state; 37};
39 38
40/* We can't use the sub-second values here but they're included 39/* We can't use the sub-second values here but they're included
41 * for completeness. */ 40 * for completeness. */
42static struct { 41static struct {
43 int time; /* Seconds */ 42 unsigned int time; /* Seconds */
44 u16 val; /* WDOG_TO value */ 43 u16 val; /* WDOG_TO value */
45} wm831x_wdt_cfgs[] = { 44} wm831x_wdt_cfgs[] = {
46 { 1, 2 }, 45 { 1, 2 },
47 { 2, 3 }, 46 { 2, 3 },
@@ -52,32 +51,13 @@ static struct {
52 { 33, 7 }, /* Actually 32.768s so include both, others round down */ 51 { 33, 7 }, /* Actually 32.768s so include both, others round down */
53}; 52};
54 53
55static int wm831x_wdt_set_timeout(struct wm831x *wm831x, u16 value) 54static int wm831x_wdt_start(struct watchdog_device *wdt_dev)
56{
57 int ret;
58
59 mutex_lock(&wdt_mutex);
60
61 ret = wm831x_reg_unlock(wm831x);
62 if (ret == 0) {
63 ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
64 WM831X_WDOG_TO_MASK, value);
65 wm831x_reg_lock(wm831x);
66 } else {
67 dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
68 ret);
69 }
70
71 mutex_unlock(&wdt_mutex);
72
73 return ret;
74}
75
76static int wm831x_wdt_start(struct wm831x *wm831x)
77{ 55{
56 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
57 struct wm831x *wm831x = driver_data->wm831x;
78 int ret; 58 int ret;
79 59
80 mutex_lock(&wdt_mutex); 60 mutex_lock(&driver_data->lock);
81 61
82 ret = wm831x_reg_unlock(wm831x); 62 ret = wm831x_reg_unlock(wm831x);
83 if (ret == 0) { 63 if (ret == 0) {
@@ -89,16 +69,18 @@ static int wm831x_wdt_start(struct wm831x *wm831x)
89 ret); 69 ret);
90 } 70 }
91 71
92 mutex_unlock(&wdt_mutex); 72 mutex_unlock(&driver_data->lock);
93 73
94 return ret; 74 return ret;
95} 75}
96 76
97static int wm831x_wdt_stop(struct wm831x *wm831x) 77static int wm831x_wdt_stop(struct watchdog_device *wdt_dev)
98{ 78{
79 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
80 struct wm831x *wm831x = driver_data->wm831x;
99 int ret; 81 int ret;
100 82
101 mutex_lock(&wdt_mutex); 83 mutex_lock(&driver_data->lock);
102 84
103 ret = wm831x_reg_unlock(wm831x); 85 ret = wm831x_reg_unlock(wm831x);
104 if (ret == 0) { 86 if (ret == 0) {
@@ -110,26 +92,28 @@ static int wm831x_wdt_stop(struct wm831x *wm831x)
110 ret); 92 ret);
111 } 93 }
112 94
113 mutex_unlock(&wdt_mutex); 95 mutex_unlock(&driver_data->lock);
114 96
115 return ret; 97 return ret;
116} 98}
117 99
118static int wm831x_wdt_kick(struct wm831x *wm831x) 100static int wm831x_wdt_ping(struct watchdog_device *wdt_dev)
119{ 101{
102 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
103 struct wm831x *wm831x = driver_data->wm831x;
120 int ret; 104 int ret;
121 u16 reg; 105 u16 reg;
122 106
123 mutex_lock(&wdt_mutex); 107 mutex_lock(&driver_data->lock);
124 108
125 if (update_gpio) { 109 if (driver_data->update_gpio) {
126 gpio_set_value_cansleep(update_gpio, update_state); 110 gpio_set_value_cansleep(driver_data->update_gpio,
127 update_state = !update_state; 111 driver_data->update_state);
112 driver_data->update_state = !driver_data->update_state;
128 ret = 0; 113 ret = 0;
129 goto out; 114 goto out;
130 } 115 }
131 116
132
133 reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 117 reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
134 118
135 if (!(reg & WM831X_WDOG_RST_SRC)) { 119 if (!(reg & WM831X_WDOG_RST_SRC)) {
@@ -150,182 +134,59 @@ static int wm831x_wdt_kick(struct wm831x *wm831x)
150 } 134 }
151 135
152out: 136out:
153 mutex_unlock(&wdt_mutex); 137 mutex_unlock(&driver_data->lock);
154 138
155 return ret; 139 return ret;
156} 140}
157 141
158static int wm831x_wdt_open(struct inode *inode, struct file *file) 142static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev,
143 unsigned int timeout)
159{ 144{
160 int ret; 145 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
161 146 struct wm831x *wm831x = driver_data->wm831x;
162 if (!wm831x) 147 int ret, i;
163 return -ENODEV;
164
165 if (test_and_set_bit(0, &wm831x_wdt_users))
166 return -EBUSY;
167 148
168 ret = wm831x_wdt_start(wm831x); 149 for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
169 if (ret != 0) 150 if (wm831x_wdt_cfgs[i].time == timeout)
170 return ret; 151 break;
171 152 if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
172 return nonseekable_open(inode, file); 153 ret = -EINVAL;
173}
174 154
175static int wm831x_wdt_release(struct inode *inode, struct file *file) 155 ret = wm831x_reg_unlock(wm831x);
176{ 156 if (ret == 0) {
177 if (wm831x_wdt_expect_close) 157 ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
178 wm831x_wdt_stop(wm831x); 158 WM831X_WDOG_TO_MASK,
179 else { 159 wm831x_wdt_cfgs[i].val);
180 dev_warn(wm831x->dev, "Watchdog device closed uncleanly\n"); 160 wm831x_reg_lock(wm831x);
181 wm831x_wdt_kick(wm831x); 161 } else {
162 dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
163 ret);
182 } 164 }
183 165
184 clear_bit(0, &wm831x_wdt_users); 166 return ret;
185
186 return 0;
187}
188
189static ssize_t wm831x_wdt_write(struct file *file,
190 const char __user *data, size_t count,
191 loff_t *ppos)
192{
193 size_t i;
194
195 if (count) {
196 wm831x_wdt_kick(wm831x);
197
198 if (!nowayout) {
199 /* In case it was set long ago */
200 wm831x_wdt_expect_close = 0;
201
202 /* scan to see whether or not we got the magic
203 character */
204 for (i = 0; i != count; i++) {
205 char c;
206 if (get_user(c, data + i))
207 return -EFAULT;
208 if (c == 'V')
209 wm831x_wdt_expect_close = 42;
210 }
211 }
212 }
213 return count;
214} 167}
215 168
216static const struct watchdog_info ident = { 169static const struct watchdog_info wm831x_wdt_info = {
217 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 170 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
218 .identity = "WM831x Watchdog", 171 .identity = "WM831x Watchdog",
219}; 172};
220 173
221static long wm831x_wdt_ioctl(struct file *file, unsigned int cmd, 174static const struct watchdog_ops wm831x_wdt_ops = {
222 unsigned long arg)
223{
224 int ret = -ENOTTY, time, i;
225 void __user *argp = (void __user *)arg;
226 int __user *p = argp;
227 u16 reg;
228
229 switch (cmd) {
230 case WDIOC_GETSUPPORT:
231 ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
232 break;
233
234 case WDIOC_GETSTATUS:
235 case WDIOC_GETBOOTSTATUS:
236 ret = put_user(0, p);
237 break;
238
239 case WDIOC_SETOPTIONS:
240 {
241 int options;
242
243 if (get_user(options, p))
244 return -EFAULT;
245
246 ret = -EINVAL;
247
248 /* Setting both simultaneously means at least one must fail */
249 if (options == WDIOS_DISABLECARD)
250 ret = wm831x_wdt_start(wm831x);
251
252 if (options == WDIOS_ENABLECARD)
253 ret = wm831x_wdt_stop(wm831x);
254 break;
255 }
256
257 case WDIOC_KEEPALIVE:
258 ret = wm831x_wdt_kick(wm831x);
259 break;
260
261 case WDIOC_SETTIMEOUT:
262 ret = get_user(time, p);
263 if (ret)
264 break;
265
266 if (time == 0) {
267 if (nowayout)
268 ret = -EINVAL;
269 else
270 wm831x_wdt_stop(wm831x);
271 break;
272 }
273
274 for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
275 if (wm831x_wdt_cfgs[i].time == time)
276 break;
277 if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
278 ret = -EINVAL;
279 else
280 ret = wm831x_wdt_set_timeout(wm831x,
281 wm831x_wdt_cfgs[i].val);
282 break;
283
284 case WDIOC_GETTIMEOUT:
285 reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
286 reg &= WM831X_WDOG_TO_MASK;
287 for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
288 if (wm831x_wdt_cfgs[i].val == reg)
289 break;
290 if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) {
291 dev_warn(wm831x->dev,
292 "Unknown watchdog configuration: %x\n", reg);
293 ret = -EINVAL;
294 } else
295 ret = put_user(wm831x_wdt_cfgs[i].time, p);
296
297 }
298
299 return ret;
300}
301
302static const struct file_operations wm831x_wdt_fops = {
303 .owner = THIS_MODULE, 175 .owner = THIS_MODULE,
304 .llseek = no_llseek, 176 .start = wm831x_wdt_start,
305 .write = wm831x_wdt_write, 177 .stop = wm831x_wdt_stop,
306 .unlocked_ioctl = wm831x_wdt_ioctl, 178 .ping = wm831x_wdt_ping,
307 .open = wm831x_wdt_open, 179 .set_timeout = wm831x_wdt_set_timeout,
308 .release = wm831x_wdt_release,
309};
310
311static struct miscdevice wm831x_wdt_miscdev = {
312 .minor = WATCHDOG_MINOR,
313 .name = "watchdog",
314 .fops = &wm831x_wdt_fops,
315}; 180};
316 181
317static int __devinit wm831x_wdt_probe(struct platform_device *pdev) 182static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
318{ 183{
184 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
319 struct wm831x_pdata *chip_pdata; 185 struct wm831x_pdata *chip_pdata;
320 struct wm831x_watchdog_pdata *pdata; 186 struct wm831x_watchdog_pdata *pdata;
321 int reg, ret; 187 struct wm831x_wdt_drvdata *driver_data;
322 188 struct watchdog_device *wm831x_wdt;
323 if (wm831x) { 189 int reg, ret, i;
324 dev_err(&pdev->dev, "wm831x watchdog already registered\n");
325 return -EBUSY;
326 }
327
328 wm831x = dev_get_drvdata(pdev->dev.parent);
329 190
330 ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 191 ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
331 if (ret < 0) { 192 if (ret < 0) {
@@ -338,6 +199,36 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
338 if (reg & WM831X_WDOG_DEBUG) 199 if (reg & WM831X_WDOG_DEBUG)
339 dev_warn(wm831x->dev, "Watchdog is paused\n"); 200 dev_warn(wm831x->dev, "Watchdog is paused\n");
340 201
202 driver_data = kzalloc(sizeof(*driver_data), GFP_KERNEL);
203 if (!driver_data) {
204 dev_err(wm831x->dev, "Unable to alloacate watchdog device\n");
205 ret = -ENOMEM;
206 goto err;
207 }
208
209 mutex_init(&driver_data->lock);
210 driver_data->wm831x = wm831x;
211
212 wm831x_wdt = &driver_data->wdt;
213
214 wm831x_wdt->info = &wm831x_wdt_info;
215 wm831x_wdt->ops = &wm831x_wdt_ops;
216 watchdog_set_drvdata(wm831x_wdt, driver_data);
217
218 if (nowayout)
219 wm831x_wdt->status |= WDOG_NO_WAY_OUT;
220
221 reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
222 reg &= WM831X_WDOG_TO_MASK;
223 for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
224 if (wm831x_wdt_cfgs[i].val == reg)
225 break;
226 if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
227 dev_warn(wm831x->dev,
228 "Unknown watchdog timeout: %x\n", reg);
229 else
230 wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time;
231
341 /* Apply any configuration */ 232 /* Apply any configuration */
342 if (pdev->dev.parent->platform_data) { 233 if (pdev->dev.parent->platform_data) {
343 chip_pdata = pdev->dev.parent->platform_data; 234 chip_pdata = pdev->dev.parent->platform_data;
@@ -361,7 +252,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
361 dev_err(wm831x->dev, 252 dev_err(wm831x->dev,
362 "Failed to request update GPIO: %d\n", 253 "Failed to request update GPIO: %d\n",
363 ret); 254 ret);
364 goto err; 255 goto err_alloc;
365 } 256 }
366 257
367 ret = gpio_direction_output(pdata->update_gpio, 0); 258 ret = gpio_direction_output(pdata->update_gpio, 0);
@@ -372,7 +263,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
372 goto err_gpio; 263 goto err_gpio;
373 } 264 }
374 265
375 update_gpio = pdata->update_gpio; 266 driver_data->update_gpio = pdata->update_gpio;
376 267
377 /* Make sure the watchdog takes hardware updates */ 268 /* Make sure the watchdog takes hardware updates */
378 reg |= WM831X_WDOG_RST_SRC; 269 reg |= WM831X_WDOG_RST_SRC;
@@ -389,33 +280,34 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
389 } 280 }
390 } 281 }
391 282
392 wm831x_wdt_miscdev.parent = &pdev->dev; 283 ret = watchdog_register_device(&driver_data->wdt);
393
394 ret = misc_register(&wm831x_wdt_miscdev);
395 if (ret != 0) { 284 if (ret != 0) {
396 dev_err(wm831x->dev, "Failed to register miscdev: %d\n", ret); 285 dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
286 ret);
397 goto err_gpio; 287 goto err_gpio;
398 } 288 }
399 289
290 dev_set_drvdata(&pdev->dev, driver_data);
291
400 return 0; 292 return 0;
401 293
402err_gpio: 294err_gpio:
403 if (update_gpio) { 295 if (driver_data->update_gpio)
404 gpio_free(update_gpio); 296 gpio_free(driver_data->update_gpio);
405 update_gpio = 0; 297err_alloc:
406 } 298 kfree(driver_data);
407err: 299err:
408 return ret; 300 return ret;
409} 301}
410 302
411static int __devexit wm831x_wdt_remove(struct platform_device *pdev) 303static int __devexit wm831x_wdt_remove(struct platform_device *pdev)
412{ 304{
413 if (update_gpio) { 305 struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev);
414 gpio_free(update_gpio); 306
415 update_gpio = 0; 307 watchdog_unregister_device(&driver_data->wdt);
416 }
417 308
418 misc_deregister(&wm831x_wdt_miscdev); 309 if (driver_data->update_gpio)
310 gpio_free(driver_data->update_gpio);
419 311
420 return 0; 312 return 0;
421} 313}