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 __devinit wm831x_wdt_probe(struct platform_device *pdev)
 185{
 186        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
 187        struct wm831x_pdata *chip_pdata;
 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                dev_err(wm831x->dev, "Unable to alloacate watchdog device\n");
 208                ret = -ENOMEM;
 209                goto err;
 210        }
 211
 212        mutex_init(&driver_data->lock);
 213        driver_data->wm831x = wm831x;
 214
 215        wm831x_wdt = &driver_data->wdt;
 216
 217        wm831x_wdt->info = &wm831x_wdt_info;
 218        wm831x_wdt->ops = &wm831x_wdt_ops;
 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 (pdev->dev.parent->platform_data) {
 235                chip_pdata = pdev->dev.parent->platform_data;
 236                pdata = chip_pdata->watchdog;
 237        } else {
 238                pdata = NULL;
 239        }
 240
 241        if (pdata) {
 242                reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK |
 243                         WM831X_WDOG_RST_SRC);
 244
 245                reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT;
 246                reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT;
 247                reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 248
 249                if (pdata->update_gpio) {
 250                        ret = gpio_request_one(pdata->update_gpio,
 251                                               GPIOF_DIR_OUT | GPIOF_INIT_LOW,
 252                                               "Watchdog update");
 253                        if (ret < 0) {
 254                                dev_err(wm831x->dev,
 255                                        "Failed to request update GPIO: %d\n",
 256                                        ret);
 257                                goto err;
 258                        }
 259
 260                        driver_data->update_gpio = pdata->update_gpio;
 261
 262                        /* Make sure the watchdog takes hardware updates */
 263                        reg |= WM831X_WDOG_RST_SRC;
 264                }
 265
 266                ret = wm831x_reg_unlock(wm831x);
 267                if (ret == 0) {
 268                        ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
 269                        wm831x_reg_lock(wm831x);
 270                } else {
 271                        dev_err(wm831x->dev,
 272                                "Failed to unlock security key: %d\n", ret);
 273                        goto err_gpio;
 274                }
 275        }
 276
 277        ret = watchdog_register_device(&driver_data->wdt);
 278        if (ret != 0) {
 279                dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
 280                        ret);
 281                goto err_gpio;
 282        }
 283
 284        dev_set_drvdata(&pdev->dev, driver_data);
 285
 286        return 0;
 287
 288err_gpio:
 289        if (driver_data->update_gpio)
 290                gpio_free(driver_data->update_gpio);
 291err:
 292        return ret;
 293}
 294
 295static int __devexit wm831x_wdt_remove(struct platform_device *pdev)
 296{
 297        struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev);
 298
 299        watchdog_unregister_device(&driver_data->wdt);
 300
 301        if (driver_data->update_gpio)
 302                gpio_free(driver_data->update_gpio);
 303
 304        return 0;
 305}
 306
 307static struct platform_driver wm831x_wdt_driver = {
 308        .probe = wm831x_wdt_probe,
 309        .remove = __devexit_p(wm831x_wdt_remove),
 310        .driver = {
 311                .name = "wm831x-watchdog",
 312        },
 313};
 314
 315module_platform_driver(wm831x_wdt_driver);
 316
 317MODULE_AUTHOR("Mark Brown");
 318MODULE_DESCRIPTION("WM831x Watchdog");
 319MODULE_LICENSE("GPL");
 320MODULE_ALIAS("platform:wm831x-watchdog");
 321
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.