linux/drivers/watchdog/wm8350_wdt.c
<<
>>
Prefs
   1/*
   2 * Watchdog driver for the wm8350
   3 *
   4 * Copyright (C) 2007, 2008 Wolfson Microelectronics <linux@wolfsonmicro.com>
   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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12
  13#include <linux/module.h>
  14#include <linux/moduleparam.h>
  15#include <linux/types.h>
  16#include <linux/kernel.h>
  17#include <linux/platform_device.h>
  18#include <linux/watchdog.h>
  19#include <linux/uaccess.h>
  20#include <linux/mfd/wm8350/core.h>
  21
  22static bool nowayout = WATCHDOG_NOWAYOUT;
  23module_param(nowayout, bool, 0);
  24MODULE_PARM_DESC(nowayout,
  25                 "Watchdog cannot be stopped once started (default="
  26                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  27
  28static DEFINE_MUTEX(wdt_mutex);
  29
  30static struct {
  31        unsigned int time;  /* Seconds */
  32        u16 val;            /* To be set in WM8350_SYSTEM_CONTROL_2 */
  33} wm8350_wdt_cfgs[] = {
  34        { 1, 0x02 },
  35        { 2, 0x04 },
  36        { 4, 0x05 },
  37};
  38
  39static int wm8350_wdt_set_timeout(struct watchdog_device *wdt_dev,
  40                                  unsigned int timeout)
  41{
  42        struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
  43        int ret, i;
  44        u16 reg;
  45
  46        for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
  47                if (wm8350_wdt_cfgs[i].time == timeout)
  48                        break;
  49        if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
  50                return -EINVAL;
  51
  52        mutex_lock(&wdt_mutex);
  53        wm8350_reg_unlock(wm8350);
  54
  55        reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
  56        reg &= ~WM8350_WDOG_TO_MASK;
  57        reg |= wm8350_wdt_cfgs[i].val;
  58        ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
  59
  60        wm8350_reg_lock(wm8350);
  61        mutex_unlock(&wdt_mutex);
  62
  63        wdt_dev->timeout = timeout;
  64        return ret;
  65}
  66
  67static int wm8350_wdt_start(struct watchdog_device *wdt_dev)
  68{
  69        struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
  70        int ret;
  71        u16 reg;
  72
  73        mutex_lock(&wdt_mutex);
  74        wm8350_reg_unlock(wm8350);
  75
  76        reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
  77        reg &= ~WM8350_WDOG_MODE_MASK;
  78        reg |= 0x20;
  79        ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
  80
  81        wm8350_reg_lock(wm8350);
  82        mutex_unlock(&wdt_mutex);
  83
  84        return ret;
  85}
  86
  87static int wm8350_wdt_stop(struct watchdog_device *wdt_dev)
  88{
  89        struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
  90        int ret;
  91        u16 reg;
  92
  93        mutex_lock(&wdt_mutex);
  94        wm8350_reg_unlock(wm8350);
  95
  96        reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
  97        reg &= ~WM8350_WDOG_MODE_MASK;
  98        ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
  99
 100        wm8350_reg_lock(wm8350);
 101        mutex_unlock(&wdt_mutex);
 102
 103        return ret;
 104}
 105
 106static int wm8350_wdt_ping(struct watchdog_device *wdt_dev)
 107{
 108        struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
 109        int ret;
 110        u16 reg;
 111
 112        mutex_lock(&wdt_mutex);
 113
 114        reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
 115        ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
 116
 117        mutex_unlock(&wdt_mutex);
 118
 119        return ret;
 120}
 121
 122static const struct watchdog_info wm8350_wdt_info = {
 123        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 124        .identity = "WM8350 Watchdog",
 125};
 126
 127static const struct watchdog_ops wm8350_wdt_ops = {
 128        .owner = THIS_MODULE,
 129        .start = wm8350_wdt_start,
 130        .stop = wm8350_wdt_stop,
 131        .ping = wm8350_wdt_ping,
 132        .set_timeout = wm8350_wdt_set_timeout,
 133};
 134
 135static struct watchdog_device wm8350_wdt = {
 136        .info = &wm8350_wdt_info,
 137        .ops = &wm8350_wdt_ops,
 138        .timeout = 4,
 139        .min_timeout = 1,
 140        .max_timeout = 4,
 141};
 142
 143static int wm8350_wdt_probe(struct platform_device *pdev)
 144{
 145        struct wm8350 *wm8350 = platform_get_drvdata(pdev);
 146
 147        if (!wm8350) {
 148                pr_err("No driver data supplied\n");
 149                return -ENODEV;
 150        }
 151
 152        watchdog_set_nowayout(&wm8350_wdt, nowayout);
 153        watchdog_set_drvdata(&wm8350_wdt, wm8350);
 154        wm8350_wdt.parent = &pdev->dev;
 155
 156        /* Default to 4s timeout */
 157        wm8350_wdt_set_timeout(&wm8350_wdt, 4);
 158
 159        return watchdog_register_device(&wm8350_wdt);
 160}
 161
 162static int wm8350_wdt_remove(struct platform_device *pdev)
 163{
 164        watchdog_unregister_device(&wm8350_wdt);
 165        return 0;
 166}
 167
 168static struct platform_driver wm8350_wdt_driver = {
 169        .probe = wm8350_wdt_probe,
 170        .remove = wm8350_wdt_remove,
 171        .driver = {
 172                .name = "wm8350-wdt",
 173        },
 174};
 175
 176module_platform_driver(wm8350_wdt_driver);
 177
 178MODULE_AUTHOR("Mark Brown");
 179MODULE_DESCRIPTION("WM8350 Watchdog");
 180MODULE_LICENSE("GPL");
 181MODULE_ALIAS("platform:wm8350-wdt");
 182