259 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Watchdog driver for the wm831x PMICs4 *5 * Copyright (C) 2009 Wolfson Microelectronics6 */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 included35 * 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 else216 wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time;217 218 /* Apply any configuration */219 if (chip_pdata)220 pdata = chip_pdata->watchdog;221 else222 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");259