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