172 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Watchdog driver for the wm83504 *5 * Copyright (C) 2007, 2008 Wolfson Microelectronics <linux@wolfsonmicro.com>6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 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 devm_watchdog_register_device(&pdev->dev, &wm8350_wdt);157}158 159static struct platform_driver wm8350_wdt_driver = {160 .probe = wm8350_wdt_probe,161 .driver = {162 .name = "wm8350-wdt",163 },164};165 166module_platform_driver(wm8350_wdt_driver);167 168MODULE_AUTHOR("Mark Brown");169MODULE_DESCRIPTION("WM8350 Watchdog");170MODULE_LICENSE("GPL");171MODULE_ALIAS("platform:wm8350-wdt");172