Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: ts72xx_wdt: convert driver to watchdog core

Cleanup this driver and convert it to use the watchdog framework API.

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Mika Westerberg <mika.westerberg@iki.fi>
[groeck: Dropped initialization of static variable]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

H Hartley Sweeten and committed by
Guenter Roeck
8f8dc7bf 91700361

+101 -370
+101 -370
drivers/watchdog/ts72xx_wdt.c
··· 13 13 * warranty of any kind, whether express or implied. 14 14 */ 15 15 16 - #include <linux/fs.h> 17 - #include <linux/io.h> 18 - #include <linux/module.h> 19 - #include <linux/moduleparam.h> 20 - #include <linux/miscdevice.h> 21 - #include <linux/mutex.h> 22 16 #include <linux/platform_device.h> 23 - #include <linux/slab.h> 17 + #include <linux/module.h> 24 18 #include <linux/watchdog.h> 25 - #include <linux/uaccess.h> 19 + #include <linux/io.h> 26 20 27 - #define TS72XX_WDT_FEED_VAL 0x05 28 - #define TS72XX_WDT_DEFAULT_TIMEOUT 8 21 + #define TS72XX_WDT_DEFAULT_TIMEOUT 30 29 22 30 - static int timeout = TS72XX_WDT_DEFAULT_TIMEOUT; 23 + static int timeout; 31 24 module_param(timeout, int, 0); 32 - MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. " 33 - "(1 <= timeout <= 8, default=" 34 - __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT) 35 - ")"); 25 + MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds."); 36 26 37 27 static bool nowayout = WATCHDOG_NOWAYOUT; 38 28 module_param(nowayout, bool, 0); 39 29 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); 40 30 41 - /** 42 - * struct ts72xx_wdt - watchdog control structure 43 - * @lock: lock that protects this structure 44 - * @regval: watchdog timeout value suitable for control register 45 - * @flags: flags controlling watchdog device state 46 - * @control_reg: watchdog control register 47 - * @feed_reg: watchdog feed register 48 - * @pdev: back pointer to platform dev 49 - */ 50 - struct ts72xx_wdt { 51 - struct mutex lock; 52 - int regval; 31 + /* priv->control_reg */ 32 + #define TS72XX_WDT_CTRL_DISABLE 0x00 33 + #define TS72XX_WDT_CTRL_250MS 0x01 34 + #define TS72XX_WDT_CTRL_500MS 0x02 35 + #define TS72XX_WDT_CTRL_1SEC 0x03 36 + #define TS72XX_WDT_CTRL_RESERVED 0x04 37 + #define TS72XX_WDT_CTRL_2SEC 0x05 38 + #define TS72XX_WDT_CTRL_4SEC 0x06 39 + #define TS72XX_WDT_CTRL_8SEC 0x07 53 40 54 - #define TS72XX_WDT_BUSY_FLAG 1 55 - #define TS72XX_WDT_EXPECT_CLOSE_FLAG 2 56 - int flags; 41 + /* priv->feed_reg */ 42 + #define TS72XX_WDT_FEED_VAL 0x05 57 43 44 + struct ts72xx_wdt_priv { 58 45 void __iomem *control_reg; 59 46 void __iomem *feed_reg; 60 - 61 - struct platform_device *pdev; 47 + struct watchdog_device wdd; 48 + unsigned char regval; 62 49 }; 63 50 64 - static struct platform_device *ts72xx_wdt_pdev; 65 - 66 - /* 67 - * TS-72xx Watchdog supports following timeouts (value written 68 - * to control register): 69 - * value description 70 - * ------------------------- 71 - * 0x00 watchdog disabled 72 - * 0x01 250ms 73 - * 0x02 500ms 74 - * 0x03 1s 75 - * 0x04 reserved 76 - * 0x05 2s 77 - * 0x06 4s 78 - * 0x07 8s 79 - * 80 - * Timeouts below 1s are not very usable so we don't 81 - * allow them at all. 82 - * 83 - * We provide two functions that convert between these: 84 - * timeout_to_regval() and regval_to_timeout(). 85 - */ 86 - static const struct { 87 - int timeout; 88 - int regval; 89 - } ts72xx_wdt_map[] = { 90 - { 1, 3 }, 91 - { 2, 5 }, 92 - { 4, 6 }, 93 - { 8, 7 }, 94 - }; 95 - 96 - /** 97 - * timeout_to_regval() - converts given timeout to control register value 98 - * @new_timeout: timeout in seconds to be converted 99 - * 100 - * Function converts given @new_timeout into valid value that can 101 - * be programmed into watchdog control register. When conversion is 102 - * not possible, function returns %-EINVAL. 103 - */ 104 - static int timeout_to_regval(int new_timeout) 51 + static int ts72xx_wdt_start(struct watchdog_device *wdd) 105 52 { 106 - int i; 53 + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); 107 54 108 - /* first limit it to 1 - 8 seconds */ 109 - new_timeout = clamp_val(new_timeout, 1, 8); 55 + writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); 56 + writeb(priv->regval, priv->control_reg); 110 57 111 - for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) { 112 - if (ts72xx_wdt_map[i].timeout >= new_timeout) 113 - return ts72xx_wdt_map[i].regval; 114 - } 115 - 116 - return -EINVAL; 117 - } 118 - 119 - /** 120 - * regval_to_timeout() - converts control register value to timeout 121 - * @regval: control register value to be converted 122 - * 123 - * Function converts given @regval to timeout in seconds (1, 2, 4 or 8). 124 - * If @regval cannot be converted, function returns %-EINVAL. 125 - */ 126 - static int regval_to_timeout(int regval) 127 - { 128 - int i; 129 - 130 - for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) { 131 - if (ts72xx_wdt_map[i].regval == regval) 132 - return ts72xx_wdt_map[i].timeout; 133 - } 134 - 135 - return -EINVAL; 136 - } 137 - 138 - /** 139 - * ts72xx_wdt_kick() - kick the watchdog 140 - * @wdt: watchdog to be kicked 141 - * 142 - * Called with @wdt->lock held. 143 - */ 144 - static inline void ts72xx_wdt_kick(struct ts72xx_wdt *wdt) 145 - { 146 - __raw_writeb(TS72XX_WDT_FEED_VAL, wdt->feed_reg); 147 - } 148 - 149 - /** 150 - * ts72xx_wdt_start() - starts the watchdog timer 151 - * @wdt: watchdog to be started 152 - * 153 - * This function programs timeout to watchdog timer 154 - * and starts it. 155 - * 156 - * Called with @wdt->lock held. 157 - */ 158 - static void ts72xx_wdt_start(struct ts72xx_wdt *wdt) 159 - { 160 - /* 161 - * To program the wdt, it first must be "fed" and 162 - * only after that (within 30 usecs) the configuration 163 - * can be changed. 164 - */ 165 - ts72xx_wdt_kick(wdt); 166 - __raw_writeb((u8)wdt->regval, wdt->control_reg); 167 - } 168 - 169 - /** 170 - * ts72xx_wdt_stop() - stops the watchdog timer 171 - * @wdt: watchdog to be stopped 172 - * 173 - * Called with @wdt->lock held. 174 - */ 175 - static void ts72xx_wdt_stop(struct ts72xx_wdt *wdt) 176 - { 177 - ts72xx_wdt_kick(wdt); 178 - __raw_writeb(0, wdt->control_reg); 179 - } 180 - 181 - static int ts72xx_wdt_open(struct inode *inode, struct file *file) 182 - { 183 - struct ts72xx_wdt *wdt = platform_get_drvdata(ts72xx_wdt_pdev); 184 - int regval; 185 - 186 - /* 187 - * Try to convert default timeout to valid register 188 - * value first. 189 - */ 190 - regval = timeout_to_regval(timeout); 191 - if (regval < 0) { 192 - dev_err(&wdt->pdev->dev, 193 - "failed to convert timeout (%d) to register value\n", 194 - timeout); 195 - return regval; 196 - } 197 - 198 - if (mutex_lock_interruptible(&wdt->lock)) 199 - return -ERESTARTSYS; 200 - 201 - if ((wdt->flags & TS72XX_WDT_BUSY_FLAG) != 0) { 202 - mutex_unlock(&wdt->lock); 203 - return -EBUSY; 204 - } 205 - 206 - wdt->flags = TS72XX_WDT_BUSY_FLAG; 207 - wdt->regval = regval; 208 - file->private_data = wdt; 209 - 210 - ts72xx_wdt_start(wdt); 211 - 212 - mutex_unlock(&wdt->lock); 213 - return nonseekable_open(inode, file); 214 - } 215 - 216 - static int ts72xx_wdt_release(struct inode *inode, struct file *file) 217 - { 218 - struct ts72xx_wdt *wdt = file->private_data; 219 - 220 - if (mutex_lock_interruptible(&wdt->lock)) 221 - return -ERESTARTSYS; 222 - 223 - if ((wdt->flags & TS72XX_WDT_EXPECT_CLOSE_FLAG) != 0) { 224 - ts72xx_wdt_stop(wdt); 225 - } else { 226 - dev_warn(&wdt->pdev->dev, 227 - "TS-72XX WDT device closed unexpectly. " 228 - "Watchdog timer will not stop!\n"); 229 - /* 230 - * Kick it one more time, to give userland some time 231 - * to recover (for example, respawning the kicker 232 - * daemon). 233 - */ 234 - ts72xx_wdt_kick(wdt); 235 - } 236 - 237 - wdt->flags = 0; 238 - 239 - mutex_unlock(&wdt->lock); 240 58 return 0; 241 59 } 242 60 243 - static ssize_t ts72xx_wdt_write(struct file *file, 244 - const char __user *data, 245 - size_t len, 246 - loff_t *ppos) 61 + static int ts72xx_wdt_stop(struct watchdog_device *wdd) 247 62 { 248 - struct ts72xx_wdt *wdt = file->private_data; 63 + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); 249 64 250 - if (!len) 251 - return 0; 65 + writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); 66 + writeb(TS72XX_WDT_CTRL_DISABLE, priv->control_reg); 252 67 253 - if (mutex_lock_interruptible(&wdt->lock)) 254 - return -ERESTARTSYS; 255 - 256 - ts72xx_wdt_kick(wdt); 257 - 258 - /* 259 - * Support for magic character closing. User process 260 - * writes 'V' into the device, just before it is closed. 261 - * This means that we know that the wdt timer can be 262 - * stopped after user closes the device. 263 - */ 264 - if (!nowayout) { 265 - int i; 266 - 267 - for (i = 0; i < len; i++) { 268 - char c; 269 - 270 - /* In case it was set long ago */ 271 - wdt->flags &= ~TS72XX_WDT_EXPECT_CLOSE_FLAG; 272 - 273 - if (get_user(c, data + i)) { 274 - mutex_unlock(&wdt->lock); 275 - return -EFAULT; 276 - } 277 - if (c == 'V') { 278 - wdt->flags |= TS72XX_WDT_EXPECT_CLOSE_FLAG; 279 - break; 280 - } 281 - } 282 - } 283 - 284 - mutex_unlock(&wdt->lock); 285 - return len; 68 + return 0; 286 69 } 287 70 288 - static const struct watchdog_info winfo = { 289 - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | 71 + static int ts72xx_wdt_ping(struct watchdog_device *wdd) 72 + { 73 + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); 74 + 75 + writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); 76 + 77 + return 0; 78 + } 79 + 80 + static int ts72xx_wdt_settimeout(struct watchdog_device *wdd, unsigned int to) 81 + { 82 + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); 83 + 84 + if (to == 1) { 85 + priv->regval = TS72XX_WDT_CTRL_1SEC; 86 + } else if (to == 2) { 87 + priv->regval = TS72XX_WDT_CTRL_2SEC; 88 + } else if (to <= 4) { 89 + priv->regval = TS72XX_WDT_CTRL_4SEC; 90 + to = 4; 91 + } else { 92 + priv->regval = TS72XX_WDT_CTRL_8SEC; 93 + if (to <= 8) 94 + to = 8; 95 + } 96 + 97 + wdd->timeout = to; 98 + 99 + if (watchdog_active(wdd)) { 100 + ts72xx_wdt_stop(wdd); 101 + ts72xx_wdt_start(wdd); 102 + } 103 + 104 + return 0; 105 + } 106 + 107 + static const struct watchdog_info ts72xx_wdt_ident = { 108 + .options = WDIOF_KEEPALIVEPING | 109 + WDIOF_SETTIMEOUT | 290 110 WDIOF_MAGICCLOSE, 291 111 .firmware_version = 1, 292 112 .identity = "TS-72XX WDT", 293 113 }; 294 114 295 - static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd, 296 - unsigned long arg) 297 - { 298 - struct ts72xx_wdt *wdt = file->private_data; 299 - void __user *argp = (void __user *)arg; 300 - int __user *p = (int __user *)argp; 301 - int error = 0; 302 - 303 - if (mutex_lock_interruptible(&wdt->lock)) 304 - return -ERESTARTSYS; 305 - 306 - switch (cmd) { 307 - case WDIOC_GETSUPPORT: 308 - if (copy_to_user(argp, &winfo, sizeof(winfo))) 309 - error = -EFAULT; 310 - break; 311 - 312 - case WDIOC_GETSTATUS: 313 - case WDIOC_GETBOOTSTATUS: 314 - error = put_user(0, p); 315 - break; 316 - 317 - case WDIOC_KEEPALIVE: 318 - ts72xx_wdt_kick(wdt); 319 - break; 320 - 321 - case WDIOC_SETOPTIONS: { 322 - int options; 323 - 324 - error = get_user(options, p); 325 - if (error) 326 - break; 327 - 328 - error = -EINVAL; 329 - 330 - if ((options & WDIOS_DISABLECARD) != 0) { 331 - ts72xx_wdt_stop(wdt); 332 - error = 0; 333 - } 334 - if ((options & WDIOS_ENABLECARD) != 0) { 335 - ts72xx_wdt_start(wdt); 336 - error = 0; 337 - } 338 - 339 - break; 340 - } 341 - 342 - case WDIOC_SETTIMEOUT: { 343 - int new_timeout; 344 - int regval; 345 - 346 - error = get_user(new_timeout, p); 347 - if (error) 348 - break; 349 - 350 - regval = timeout_to_regval(new_timeout); 351 - if (regval < 0) { 352 - error = regval; 353 - break; 354 - } 355 - ts72xx_wdt_stop(wdt); 356 - wdt->regval = regval; 357 - ts72xx_wdt_start(wdt); 358 - 359 - /*FALLTHROUGH*/ 360 - } 361 - 362 - case WDIOC_GETTIMEOUT: 363 - error = put_user(regval_to_timeout(wdt->regval), p); 364 - break; 365 - 366 - default: 367 - error = -ENOTTY; 368 - break; 369 - } 370 - 371 - mutex_unlock(&wdt->lock); 372 - return error; 373 - } 374 - 375 - static const struct file_operations ts72xx_wdt_fops = { 115 + static struct watchdog_ops ts72xx_wdt_ops = { 376 116 .owner = THIS_MODULE, 377 - .llseek = no_llseek, 378 - .open = ts72xx_wdt_open, 379 - .release = ts72xx_wdt_release, 380 - .write = ts72xx_wdt_write, 381 - .unlocked_ioctl = ts72xx_wdt_ioctl, 382 - }; 383 - 384 - static struct miscdevice ts72xx_wdt_miscdev = { 385 - .minor = WATCHDOG_MINOR, 386 - .name = "watchdog", 387 - .fops = &ts72xx_wdt_fops, 117 + .start = ts72xx_wdt_start, 118 + .stop = ts72xx_wdt_stop, 119 + .ping = ts72xx_wdt_ping, 120 + .set_timeout = ts72xx_wdt_settimeout, 388 121 }; 389 122 390 123 static int ts72xx_wdt_probe(struct platform_device *pdev) 391 124 { 392 - struct ts72xx_wdt *wdt; 393 - struct resource *r1, *r2; 394 - int error = 0; 125 + struct ts72xx_wdt_priv *priv; 126 + struct watchdog_device *wdd; 127 + struct resource *res; 128 + int ret; 395 129 396 - wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL); 397 - if (!wdt) 130 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 131 + if (!priv) 398 132 return -ENOMEM; 399 133 400 - r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 401 - wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1); 402 - if (IS_ERR(wdt->control_reg)) 403 - return PTR_ERR(wdt->control_reg); 134 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 135 + priv->control_reg = devm_ioremap_resource(&pdev->dev, res); 136 + if (IS_ERR(priv->control_reg)) 137 + return PTR_ERR(priv->control_reg); 404 138 405 - r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 406 - wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2); 407 - if (IS_ERR(wdt->feed_reg)) 408 - return PTR_ERR(wdt->feed_reg); 139 + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 140 + priv->feed_reg = devm_ioremap_resource(&pdev->dev, res); 141 + if (IS_ERR(priv->feed_reg)) 142 + return PTR_ERR(priv->feed_reg); 409 143 410 - platform_set_drvdata(pdev, wdt); 411 - ts72xx_wdt_pdev = pdev; 412 - wdt->pdev = pdev; 413 - mutex_init(&wdt->lock); 144 + wdd = &priv->wdd; 145 + wdd->info = &ts72xx_wdt_ident; 146 + wdd->ops = &ts72xx_wdt_ops; 147 + wdd->min_timeout = 1; 148 + wdd->max_hw_heartbeat_ms = 8000; 149 + wdd->parent = &pdev->dev; 414 150 415 - /* make sure that the watchdog is disabled */ 416 - ts72xx_wdt_stop(wdt); 151 + watchdog_set_nowayout(wdd, nowayout); 417 152 418 - error = misc_register(&ts72xx_wdt_miscdev); 419 - if (error) { 420 - dev_err(&pdev->dev, "failed to register miscdev\n"); 421 - return error; 422 - } 153 + wdd->timeout = TS72XX_WDT_DEFAULT_TIMEOUT; 154 + watchdog_init_timeout(wdd, timeout, &pdev->dev); 155 + 156 + watchdog_set_drvdata(wdd, priv); 157 + 158 + ret = devm_watchdog_register_device(&pdev->dev, wdd); 159 + if (ret) 160 + return ret; 423 161 424 162 dev_info(&pdev->dev, "TS-72xx Watchdog driver\n"); 425 163 426 164 return 0; 427 165 } 428 166 429 - static int ts72xx_wdt_remove(struct platform_device *pdev) 430 - { 431 - misc_deregister(&ts72xx_wdt_miscdev); 432 - return 0; 433 - } 434 - 435 167 static struct platform_driver ts72xx_wdt_driver = { 436 168 .probe = ts72xx_wdt_probe, 437 - .remove = ts72xx_wdt_remove, 438 169 .driver = { 439 170 .name = "ts72xx-wdt", 440 171 },