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/slab.h>
  16#include <linux/platform_device.h>
  17#include <linux/watchdog.h>
  18#include <linux/uaccess.h>
  19#include <linux/gpio.h>
  20
  21#include <linux/mfd/wm831x/core.h>
  22#include <linux/mfd/wm831x/pdata.h>
  23#include <linux/mfd/wm831x/watchdog.h>
  24
  25static bool nowayout = WATCHDOG_NOWAYOUT;
  26module_param(nowayout, bool, 0);
  27MODULE_PARM_DESC(nowayout,
  28                 "Watchdog cannot be stopped once started (default="
  29                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  30
  31struct wm831x_wdt_drvdata {
  32        struct watchdog_device wdt;
  33        struct wm831x *wm831x;
  34        struct mutex lock;
  35        int update_gpio;
  36        int update_state;
  37};
  38
  39/* We can't use the sub-second values here but they're included
  40 * for completeness.  */
  41static struct {
  42        unsigned int time;  /* Seconds */
  43        u16 val;            /* WDOG_TO value */
  44} wm831x_wdt_cfgs[] = {
  45        {  1, 2 },
  46        {  2, 3 },
  47        {  4, 4 },
  48        {  8, 5 },
  49        { 16, 6 },
  50        { 32, 7 },
  51        { 33, 7 },  /* Actually 32.768s so include both, others round down */
  52};
  53
  54static int wm831x_wdt_start(struct watchdog_device *wdt_dev)
  55{
  56        struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
  57        struct wm831x *wm831x = driver_data->wm831x;
  58        int ret;
  59
  60        mutex_lock(&driver_data->lock);
  61
  62        ret = wm831x_reg_unlock(wm831x);
  63        if (ret == 0) {
  64                ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
  65                                      WM831X_WDOG_ENA, WM831X_WDOG_ENA);
  66                wm831x_reg_lock(wm831x);
  67        } else {
  68                dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
  69                        ret);
  70        }
  71
  72        mutex_unlock(&driver_data->lock);
  73
  74        return ret;
  75}
  76
  77static int wm831x_wdt_stop(struct watchdog_device *wdt_dev)
  78{
  79        struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
  80        struct wm831x *wm831x = driver_data->wm831x;
  81        int ret;
  82
  83        mutex_lock(&driver_data->lock);
  84
  85        ret = wm831x_reg_unlock(wm831x);
  86        if (ret == 0) {
  87                ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
  88                                      WM831X_WDOG_ENA, 0);
  89                wm831x_reg_lock(wm831x);
  90        } else {
  91                dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
  92                        ret);
  93        }
  94
  95        mutex_unlock(&driver_data->lock);
  96
  97        return ret;
  98}
  99
 100static int wm831x_wdt_ping(struct watchdog_device *wdt_dev)
 101{
 102        struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
 103        struct wm831x *wm831x = driver_data->wm831x;
 104        int ret;
 105        u16 reg;
 106
 107        mutex_lock(&driver_data->lock);
 108
 109        if (driver_data->update_gpio) {
 110                gpio_set_value_cansleep(driver_data->update_gpio,
 111                                        driver_data->update_state);
 112                driver_data->update_state = !driver_data->update_state;
 113                ret = 0;
 114                goto out;
 115        }
 116
 117        reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
 118
 119        if (!(reg & WM831X_WDOG_RST_SRC)) {
 120                dev_err(wm831x->dev, "Hardware watchdog update unsupported\n");
 121                ret = -EINVAL;
 122                goto out;
 123        }
 124
 125        reg |= WM831X_WDOG_RESET;
 126
 127        ret = wm831x_reg_unlock(wm831x);
 128        if (ret == 0) {
 129                ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
 130                wm831x_reg_lock(wm831x);
 131        } else {
 132                dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
 133                        ret);
 134        }
 135
 136out:
 137        mutex_unlock(&driver_data->lock);
 138
 139        return ret;
 140}
 141
 142static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev,
 143                                  unsigned int timeout)
 144{
 145        struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
 146        struct wm831x *wm831x = driver_data->wm831x;
 147        int ret, i;
 148
 149        for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
 150                if (wm831x_wdt_cfgs[i].time == timeout)
 151                        break;
 152        if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
 153                return -EINVAL;
 154
 155        ret = wm831x_reg_unlock(wm831x);
 156        if (ret == 0) {
 157                ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
 158                                      WM831X_WDOG_TO_MASK,
 159                                      wm831x_wdt_cfgs[i].val);
 160                wm831x_reg_lock(wm831x);
 161        } else {
 162                dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
 163                        ret);
 164        }
 165
 166        wdt_dev->timeout = timeout;
 167
 168        return ret;
 169}
 170
 171static const struct watchdog_info wm831x_wdt_info = {
 172        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 173        .identity = "WM831x Watchdog",
 174};
 175
 176static const struct watchdog_ops wm831x_wdt_ops = {
 177        .owner = THIS_MODULE,
 178        .start = wm831x_wdt_start,
 179        .stop = wm831x_wdt_stop,
 180        .ping = wm831x_wdt_ping,
 181        .set_timeout = wm831x_wdt_set_timeout,
 182};
 183
 184static int wm831x_wdt_probe(struct platform_device *pdev)
 185{
 186        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
 187        struct wm831x_pdata *chip_pdata = dev_get_platdata(pdev->dev.parent);
 188        struct wm831x_watchdog_pdata *pdata;
 189        struct wm831x_wdt_drvdata *driver_data;
 190        struct watchdog_device *wm831x_wdt;
 191        int reg, ret, i;
 192
 193        ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
 194        if (ret < 0) {
 195                dev_err(wm831x->dev, "Failed to read watchdog status: %d\n",
 196                        ret);
 197                goto err;
 198        }
 199        reg = ret;
 200
 201        if (reg & WM831X_WDOG_DEBUG)
 202                dev_warn(wm831x->dev, "Watchdog is paused\n");
 203
 204        driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
 205                                   GFP_KERNEL);
 206        if (!driver_data) {
 207                ret = -ENOMEM;
 208                goto err;
 209        }
 210
 211        mutex_init(&driver_data->lock);
 212        driver_data->wm831x = wm831x;
 213
 214        wm831x_wdt = &driver_data->wdt;
 215
 216        wm831x_wdt->info = &wm831x_wdt_info;
 217        wm831x_wdt->ops = &wm831x_wdt_ops;
 218        wm831x_wdt->parent = &pdev->dev;
 219        watchdog_set_nowayout(wm831x_wdt, nowayout);
 220        watchdog_set_drvdata(wm831x_wdt, driver_data);
 221
 222        reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
 223        reg &= WM831X_WDOG_TO_MASK;
 224        for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
 225                if (wm831x_wdt_cfgs[i].val == reg)
 226                        break;
 227        if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
 228                dev_warn(wm831x->dev,
 229                         "Unknown watchdog timeout: %x\n", reg);
 230        else
 231                wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time;
 232
 233        /* Apply any configuration */
 234        if (chip_pdata)
 235                pdata = chip_pdata->watchdog;
 236        else
 237                pdata = NULL;
 238
 239        if (pdata) {
 240                reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK |
 241                         WM831X_WDOG_RST_SRC);
 242
 243                reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT;
 244                reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT;
 245                reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 246
 247                if (pdata->update_gpio) {
 248                        ret = devm_gpio_request_one(&pdev->dev,
 249                                                pdata->update_gpio,
 250                                                GPIOF_OUT_INIT_LOW,
 251                                                "Watchdog update");
 252                        if (ret < 0) {
 253                                dev_err(wm831x->dev,
 254                                        "Failed to request update GPIO: %d\n",
 255                                        ret);
 256                                goto err;
 257                        }
 258
 259                        driver_data->update_gpio = pdata->update_gpio;
 260
 261                        /* Make sure the watchdog takes hardware updates */
 262                        reg |= WM831X_WDOG_RST_SRC;
 263                }
 264
 265                ret = wm831x_reg_unlock(wm831x);
 266                if (ret == 0) {
 267                        ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
 268                        wm831x_reg_lock(wm831x);
 269                } else {
 270                        dev_err(wm831x->dev,
 271                                "Failed to unlock security key: %d\n", ret);
 272                        goto err;
 273                }
 274        }
 275
 276        ret = watchdog_register_device(&driver_data->wdt);
 277        if (ret != 0) {
 278                dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
 279                        ret);
 280                goto err;
 281        }
 282
 283        platform_set_drvdata(pdev, driver_data);
 284
 285        return 0;
 286
 287err:
 288        return ret;
 289}
 290
 291static int wm831x_wdt_remove(struct platform_device *pdev)
 292{
 293        struct wm831x_wdt_drvdata *driver_data = platform_get_drvdata(pdev);
 294
 295        watchdog_unregister_device(&driver_data->wdt);
 296
 297        return 0;
 298}
 299
 300static struct platform_driver wm831x_wdt_driver = {
 301        .probe = wm831x_wdt_probe,
 302        .remove = wm831x_wdt_remove,
 303        .driver = {
 304                .name = "wm831x-watchdog",
 305        },
 306};
 307
 308module_platform_driver(wm831x_wdt_driver);
 309
 310MODULE_AUTHOR("Mark Brown");
 311MODULE_DESCRIPTION("WM831x Watchdog");
 312MODULE_LICENSE("GPL");
 313MODULE_ALIAS("platform:wm831x-watchdog");
 314