linux/drivers/watchdog/wm831x_wdt.c
<<
>>
Prefs
   1/*
   2 * Watchdog driver for the wm831x PMICs
   3 *
   4 * Copyright (C) 2009 Wolfson Microelectronics
   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#include <linux/module.h>
  12#include <linux/moduleparam.h>
  13#include <linux/types.h>
  14#include <linux/kernel.h>
  15#include <linux/fs.h>
  16#include <linux/miscdevice.h>
  17#include <linux/platform_device.h>
  18#include <linux/watchdog.h>
  19#include <linux/uaccess.h>
  20#include <linux/gpio.h>
  21
  22#include <linux/mfd/wm831x/core.h>
  23#include <linux/mfd/wm831x/pdata.h>
  24#include <linux/mfd/wm831x/watchdog.h>
  25
  26static int nowayout = WATCHDOG_NOWAYOUT;
  27module_param(nowayout, int, 0);
  28MODULE_PARM_DESC(nowayout,
  29                 "Watchdog cannot be stopped once started (default="
  30                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  31
  32static unsigned long wm831x_wdt_users;
  33static struct miscdevice wm831x_wdt_miscdev;
  34static int wm831x_wdt_expect_close;
  35static DEFINE_MUTEX(wdt_mutex);
  36static struct wm831x *wm831x;
  37static unsigned int update_gpio;
  38static unsigned int update_state;
  39
  40/* We can't use the sub-second values here but they're included
  41 * for completeness.  */
  42static struct {
  43        int time;  /* Seconds */
  44        u16 val;   /* WDOG_TO value */
  45} wm831x_wdt_cfgs[] = {
  46        {  1, 2 },
  47        {  2, 3 },
  48        {  4, 4 },
  49        {  8, 5 },
  50        { 16, 6 },
  51        { 32, 7 },
  52        { 33, 7 },  /* Actually 32.768s so include both, others round down */
  53};
  54
  55static int wm831x_wdt_set_timeout(struct wm831x *wm831x, u16 value)
  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{
  78        int ret;
  79
  80        mutex_lock(&wdt_mutex);
  81
  82        ret = wm831x_reg_unlock(wm831x);
  83        if (ret == 0) {
  84                ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
  85                                      WM831X_WDOG_ENA, WM831X_WDOG_ENA);
  86                wm831x_reg_lock(wm831x);
  87        } else {
  88                dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
  89                        ret);
  90        }
  91
  92        mutex_unlock(&wdt_mutex);
  93
  94        return ret;
  95}
  96
  97static int wm831x_wdt_stop(struct wm831x *wm831x)
  98{
  99        int ret;
 100
 101        mutex_lock(&wdt_mutex);
 102
 103        ret = wm831x_reg_unlock(wm831x);
 104        if (ret == 0) {
 105                ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
 106                                      WM831X_WDOG_ENA, 0);
 107                wm831x_reg_lock(wm831x);
 108        } else {
 109                dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
 110                        ret);
 111        }
 112
 113        mutex_unlock(&wdt_mutex);
 114
 115        return ret;
 116}
 117
 118static int wm831x_wdt_kick(struct wm831x *wm831x)
 119{
 120        int ret;
 121        u16 reg;
 122
 123        mutex_lock(&wdt_mutex);
 124
 125        if (update_gpio) {
 126                gpio_set_value_cansleep(update_gpio, update_state);
 127                update_state = !update_state;
 128                ret = 0;
 129                goto out;
 130        }
 131
 132
 133        reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
 134
 135        if (!(reg & WM831X_WDOG_RST_SRC)) {
 136                dev_err(wm831x->dev, "Hardware watchdog update unsupported\n");
 137                ret = -EINVAL;
 138                goto out;
 139        }
 140
 141        reg |= WM831X_WDOG_RESET;
 142
 143        ret = wm831x_reg_unlock(wm831x);
 144        if (ret == 0) {
 145                ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
 146                wm831x_reg_lock(wm831x);
 147        } else {
 148                dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
 149                        ret);
 150        }
 151
 152out:
 153        mutex_unlock(&wdt_mutex);
 154
 155        return ret;
 156}
 157
 158static int wm831x_wdt_open(struct inode *inode, struct file *file)
 159{
 160        int ret;
 161
 162        if (!wm831x)
 163                return -ENODEV;
 164
 165        if (test_and_set_bit(0, &wm831x_wdt_users))
 166                return -EBUSY;
 167
 168        ret = wm831x_wdt_start(wm831x);
 169        if (ret != 0)
 170                return ret;
 171
 172        return nonseekable_open(inode, file);
 173}
 174
 175static int wm831x_wdt_release(struct inode *inode, struct file *file)
 176{
 177        if (wm831x_wdt_expect_close)
 178                wm831x_wdt_stop(wm831x);
 179        else {
 180                dev_warn(wm831x->dev, "Watchdog device closed uncleanly\n");
 181                wm831x_wdt_kick(wm831x);
 182        }
 183
 184        clear_bit(0, &wm831x_wdt_users);
 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}
 215
 216static struct watchdog_info ident = {
 217        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 218        .identity = "WM831x Watchdog",
 219};
 220
 221static long wm831x_wdt_ioctl(struct file *file, unsigned int cmd,
 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,
 304        .llseek = no_llseek,
 305        .write = wm831x_wdt_write,
 306        .unlocked_ioctl = wm831x_wdt_ioctl,
 307        .open = wm831x_wdt_open,
 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};
 316
 317static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
 318{
 319        struct wm831x_pdata *chip_pdata;
 320        struct wm831x_watchdog_pdata *pdata;
 321        int reg, ret;
 322
 323        wm831x = dev_get_drvdata(pdev->dev.parent);
 324
 325        ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
 326        if (ret < 0) {
 327                dev_err(wm831x->dev, "Failed to read watchdog status: %d\n",
 328                        ret);
 329                goto err;
 330        }
 331        reg = ret;
 332
 333        if (reg & WM831X_WDOG_DEBUG)
 334                dev_warn(wm831x->dev, "Watchdog is paused\n");
 335
 336        /* Apply any configuration */
 337        if (pdev->dev.parent->platform_data) {
 338                chip_pdata = pdev->dev.parent->platform_data;
 339                pdata = chip_pdata->watchdog;
 340        } else {
 341                pdata = NULL;
 342        }
 343
 344        if (pdata) {
 345                reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK |
 346                         WM831X_WDOG_RST_SRC);
 347
 348                reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT;
 349                reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT;
 350                reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 351
 352                if (pdata->update_gpio) {
 353                        ret = gpio_request(pdata->update_gpio,
 354                                           "Watchdog update");
 355                        if (ret < 0) {
 356                                dev_err(wm831x->dev,
 357                                        "Failed to request update GPIO: %d\n",
 358                                        ret);
 359                                goto err;
 360                        }
 361
 362                        ret = gpio_direction_output(pdata->update_gpio, 0);
 363                        if (ret != 0) {
 364                                dev_err(wm831x->dev,
 365                                        "gpio_direction_output returned: %d\n",
 366                                        ret);
 367                                goto err_gpio;
 368                        }
 369
 370                        update_gpio = pdata->update_gpio;
 371
 372                        /* Make sure the watchdog takes hardware updates */
 373                        reg |= WM831X_WDOG_RST_SRC;
 374                }
 375
 376                ret = wm831x_reg_unlock(wm831x);
 377                if (ret == 0) {
 378                        ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
 379                        wm831x_reg_lock(wm831x);
 380                } else {
 381                        dev_err(wm831x->dev,
 382                                "Failed to unlock security key: %d\n", ret);
 383                        goto err_gpio;
 384                }
 385        }
 386
 387        wm831x_wdt_miscdev.parent = &pdev->dev;
 388
 389        ret = misc_register(&wm831x_wdt_miscdev);
 390        if (ret != 0) {
 391                dev_err(wm831x->dev, "Failed to register miscdev: %d\n", ret);
 392                goto err_gpio;
 393        }
 394
 395        return 0;
 396
 397err_gpio:
 398        if (update_gpio) {
 399                gpio_free(update_gpio);
 400                update_gpio = 0;
 401        }
 402err:
 403        return ret;
 404}
 405
 406static int __devexit wm831x_wdt_remove(struct platform_device *pdev)
 407{
 408        if (update_gpio) {
 409                gpio_free(update_gpio);
 410                update_gpio = 0;
 411        }
 412
 413        misc_deregister(&wm831x_wdt_miscdev);
 414
 415        return 0;
 416}
 417
 418static struct platform_driver wm831x_wdt_driver = {
 419        .probe = wm831x_wdt_probe,
 420        .remove = __devexit_p(wm831x_wdt_remove),
 421        .driver = {
 422                .name = "wm831x-watchdog",
 423        },
 424};
 425
 426static int __init wm831x_wdt_init(void)
 427{
 428        return platform_driver_register(&wm831x_wdt_driver);
 429}
 430module_init(wm831x_wdt_init);
 431
 432static void __exit wm831x_wdt_exit(void)
 433{
 434        platform_driver_unregister(&wm831x_wdt_driver);
 435}
 436module_exit(wm831x_wdt_exit);
 437
 438MODULE_AUTHOR("Mark Brown");
 439MODULE_DESCRIPTION("WM831x Watchdog");
 440MODULE_LICENSE("GPL");
 441MODULE_ALIAS("platform:wm831x-watchdog");
 442