wm8350_wdt.c (4098B)
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");