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                return ret;
 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                return -ENOMEM;
 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        wm831x_wdt->parent = &pdev->dev;
 217        watchdog_set_nowayout(wm831x_wdt, nowayout);
 218        watchdog_set_drvdata(wm831x_wdt, driver_data);
 219
 220        reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
 221        reg &= WM831X_WDOG_TO_MASK;
 222        for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
 223                if (wm831x_wdt_cfgs[i].val == reg)
 224                        break;
 225        if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
 226                dev_warn(wm831x->dev,
 227                         "Unknown watchdog timeout: %x\n", reg);
 228        else
 229                wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time;
 230
 231        /* Apply any configuration */
 232        if (chip_pdata)
 233                pdata = chip_pdata->watchdog;
 234        else
 235                pdata = NULL;
 236
 237        if (pdata) {
 238                reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK |
 239                         WM831X_WDOG_RST_SRC);
 240
 241                reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT;
 242                reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT;
 243                reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 244
 245                if (pdata->update_gpio) {
 246                        ret = devm_gpio_request_one(&pdev->dev,
 247                                                pdata->update_gpio,
 248                                                GPIOF_OUT_INIT_LOW,
 249                                                "Watchdog update");
 250                        if (ret < 0) {
 251                                dev_err(wm831x->dev,
 252                                        "Failed to request update GPIO: %d\n",
 253                                        ret);
 254                                return ret;
 255                        }
 256
 257                        driver_data->update_gpio = pdata->update_gpio;
 258
 259                        /* Make sure the watchdog takes hardware updates */
 260                        reg |= WM831X_WDOG_RST_SRC;
 261                }
 262
 263                ret = wm831x_reg_unlock(wm831x);
 264                if (ret == 0) {
 265                        ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
 266                        wm831x_reg_lock(wm831x);
 267                } else {
 268                        dev_err(wm831x->dev,
 269                                "Failed to unlock security key: %d\n", ret);
 270                        return ret;
 271                }
 272        }
 273
 274        ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt);
 275        if (ret != 0) {
 276                dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
 277                        ret);
 278                return ret;
 279        }
 280
 281        return 0;
 282}
 283
 284static struct platform_driver wm831x_wdt_driver = {
 285        .probe = wm831x_wdt_probe,
 286        .driver = {
 287                .name = "wm831x-watchdog",
 288        },
 289};
 290
 291module_platform_driver(wm831x_wdt_driver);
 292
 293MODULE_AUTHOR("Mark Brown");
 294MODULE_DESCRIPTION("WM831x Watchdog");
 295MODULE_LICENSE("GPL");
 296MODULE_ALIAS("platform:wm831x-watchdog");
 297