wm831x_wdt.c (6333B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Watchdog driver for the wm831x PMICs 4 * 5 * Copyright (C) 2009 Wolfson Microelectronics 6 */ 7 8#include <linux/module.h> 9#include <linux/moduleparam.h> 10#include <linux/types.h> 11#include <linux/kernel.h> 12#include <linux/slab.h> 13#include <linux/platform_device.h> 14#include <linux/watchdog.h> 15#include <linux/uaccess.h> 16 17#include <linux/mfd/wm831x/core.h> 18#include <linux/mfd/wm831x/pdata.h> 19#include <linux/mfd/wm831x/watchdog.h> 20 21static bool nowayout = WATCHDOG_NOWAYOUT; 22module_param(nowayout, bool, 0); 23MODULE_PARM_DESC(nowayout, 24 "Watchdog cannot be stopped once started (default=" 25 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 26 27struct wm831x_wdt_drvdata { 28 struct watchdog_device wdt; 29 struct wm831x *wm831x; 30 struct mutex lock; 31 int update_state; 32}; 33 34/* We can't use the sub-second values here but they're included 35 * for completeness. */ 36static struct { 37 unsigned int time; /* Seconds */ 38 u16 val; /* WDOG_TO value */ 39} wm831x_wdt_cfgs[] = { 40 { 1, 2 }, 41 { 2, 3 }, 42 { 4, 4 }, 43 { 8, 5 }, 44 { 16, 6 }, 45 { 32, 7 }, 46 { 33, 7 }, /* Actually 32.768s so include both, others round down */ 47}; 48 49static int wm831x_wdt_start(struct watchdog_device *wdt_dev) 50{ 51 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); 52 struct wm831x *wm831x = driver_data->wm831x; 53 int ret; 54 55 mutex_lock(&driver_data->lock); 56 57 ret = wm831x_reg_unlock(wm831x); 58 if (ret == 0) { 59 ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, 60 WM831X_WDOG_ENA, WM831X_WDOG_ENA); 61 wm831x_reg_lock(wm831x); 62 } else { 63 dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 64 ret); 65 } 66 67 mutex_unlock(&driver_data->lock); 68 69 return ret; 70} 71 72static int wm831x_wdt_stop(struct watchdog_device *wdt_dev) 73{ 74 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); 75 struct wm831x *wm831x = driver_data->wm831x; 76 int ret; 77 78 mutex_lock(&driver_data->lock); 79 80 ret = wm831x_reg_unlock(wm831x); 81 if (ret == 0) { 82 ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, 83 WM831X_WDOG_ENA, 0); 84 wm831x_reg_lock(wm831x); 85 } else { 86 dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 87 ret); 88 } 89 90 mutex_unlock(&driver_data->lock); 91 92 return ret; 93} 94 95static int wm831x_wdt_ping(struct watchdog_device *wdt_dev) 96{ 97 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); 98 struct wm831x *wm831x = driver_data->wm831x; 99 int ret; 100 u16 reg; 101 102 mutex_lock(&driver_data->lock); 103 104 reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 105 106 if (!(reg & WM831X_WDOG_RST_SRC)) { 107 dev_err(wm831x->dev, "Hardware watchdog update unsupported\n"); 108 ret = -EINVAL; 109 goto out; 110 } 111 112 reg |= WM831X_WDOG_RESET; 113 114 ret = wm831x_reg_unlock(wm831x); 115 if (ret == 0) { 116 ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); 117 wm831x_reg_lock(wm831x); 118 } else { 119 dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 120 ret); 121 } 122 123out: 124 mutex_unlock(&driver_data->lock); 125 126 return ret; 127} 128 129static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev, 130 unsigned int timeout) 131{ 132 struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); 133 struct wm831x *wm831x = driver_data->wm831x; 134 int ret, i; 135 136 for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) 137 if (wm831x_wdt_cfgs[i].time == timeout) 138 break; 139 if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) 140 return -EINVAL; 141 142 ret = wm831x_reg_unlock(wm831x); 143 if (ret == 0) { 144 ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, 145 WM831X_WDOG_TO_MASK, 146 wm831x_wdt_cfgs[i].val); 147 wm831x_reg_lock(wm831x); 148 } else { 149 dev_err(wm831x->dev, "Failed to unlock security key: %d\n", 150 ret); 151 } 152 153 wdt_dev->timeout = timeout; 154 155 return ret; 156} 157 158static const struct watchdog_info wm831x_wdt_info = { 159 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 160 .identity = "WM831x Watchdog", 161}; 162 163static const struct watchdog_ops wm831x_wdt_ops = { 164 .owner = THIS_MODULE, 165 .start = wm831x_wdt_start, 166 .stop = wm831x_wdt_stop, 167 .ping = wm831x_wdt_ping, 168 .set_timeout = wm831x_wdt_set_timeout, 169}; 170 171static int wm831x_wdt_probe(struct platform_device *pdev) 172{ 173 struct device *dev = &pdev->dev; 174 struct wm831x *wm831x = dev_get_drvdata(dev->parent); 175 struct wm831x_pdata *chip_pdata = dev_get_platdata(dev->parent); 176 struct wm831x_watchdog_pdata *pdata; 177 struct wm831x_wdt_drvdata *driver_data; 178 struct watchdog_device *wm831x_wdt; 179 int reg, ret, i; 180 181 ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 182 if (ret < 0) { 183 dev_err(wm831x->dev, "Failed to read watchdog status: %d\n", 184 ret); 185 return ret; 186 } 187 reg = ret; 188 189 if (reg & WM831X_WDOG_DEBUG) 190 dev_warn(wm831x->dev, "Watchdog is paused\n"); 191 192 driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL); 193 if (!driver_data) 194 return -ENOMEM; 195 196 mutex_init(&driver_data->lock); 197 driver_data->wm831x = wm831x; 198 199 wm831x_wdt = &driver_data->wdt; 200 201 wm831x_wdt->info = &wm831x_wdt_info; 202 wm831x_wdt->ops = &wm831x_wdt_ops; 203 wm831x_wdt->parent = dev; 204 watchdog_set_nowayout(wm831x_wdt, nowayout); 205 watchdog_set_drvdata(wm831x_wdt, driver_data); 206 207 reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); 208 reg &= WM831X_WDOG_TO_MASK; 209 for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) 210 if (wm831x_wdt_cfgs[i].val == reg) 211 break; 212 if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) 213 dev_warn(wm831x->dev, 214 "Unknown watchdog timeout: %x\n", reg); 215 else 216 wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time; 217 218 /* Apply any configuration */ 219 if (chip_pdata) 220 pdata = chip_pdata->watchdog; 221 else 222 pdata = NULL; 223 224 if (pdata) { 225 reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK | 226 WM831X_WDOG_RST_SRC); 227 228 reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT; 229 reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT; 230 reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT; 231 232 ret = wm831x_reg_unlock(wm831x); 233 if (ret == 0) { 234 ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); 235 wm831x_reg_lock(wm831x); 236 } else { 237 dev_err(wm831x->dev, 238 "Failed to unlock security key: %d\n", ret); 239 return ret; 240 } 241 } 242 243 return devm_watchdog_register_device(dev, &driver_data->wdt); 244} 245 246static struct platform_driver wm831x_wdt_driver = { 247 .probe = wm831x_wdt_probe, 248 .driver = { 249 .name = "wm831x-watchdog", 250 }, 251}; 252 253module_platform_driver(wm831x_wdt_driver); 254 255MODULE_AUTHOR("Mark Brown"); 256MODULE_DESCRIPTION("WM831x Watchdog"); 257MODULE_LICENSE("GPL"); 258MODULE_ALIAS("platform:wm831x-watchdog");