Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Watchdog driver for the wm831x PMICs
0004  *
0005  * Copyright (C) 2009 Wolfson Microelectronics
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/moduleparam.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/slab.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/watchdog.h>
0015 #include <linux/uaccess.h>
0016 
0017 #include <linux/mfd/wm831x/core.h>
0018 #include <linux/mfd/wm831x/pdata.h>
0019 #include <linux/mfd/wm831x/watchdog.h>
0020 
0021 static bool nowayout = WATCHDOG_NOWAYOUT;
0022 module_param(nowayout, bool, 0);
0023 MODULE_PARM_DESC(nowayout,
0024          "Watchdog cannot be stopped once started (default="
0025          __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0026 
0027 struct wm831x_wdt_drvdata {
0028     struct watchdog_device wdt;
0029     struct wm831x *wm831x;
0030     struct mutex lock;
0031     int update_state;
0032 };
0033 
0034 /* We can't use the sub-second values here but they're included
0035  * for completeness.  */
0036 static struct {
0037     unsigned int time;  /* Seconds */
0038     u16 val;            /* WDOG_TO value */
0039 } wm831x_wdt_cfgs[] = {
0040     {  1, 2 },
0041     {  2, 3 },
0042     {  4, 4 },
0043     {  8, 5 },
0044     { 16, 6 },
0045     { 32, 7 },
0046     { 33, 7 },  /* Actually 32.768s so include both, others round down */
0047 };
0048 
0049 static int wm831x_wdt_start(struct watchdog_device *wdt_dev)
0050 {
0051     struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
0052     struct wm831x *wm831x = driver_data->wm831x;
0053     int ret;
0054 
0055     mutex_lock(&driver_data->lock);
0056 
0057     ret = wm831x_reg_unlock(wm831x);
0058     if (ret == 0) {
0059         ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
0060                       WM831X_WDOG_ENA, WM831X_WDOG_ENA);
0061         wm831x_reg_lock(wm831x);
0062     } else {
0063         dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
0064             ret);
0065     }
0066 
0067     mutex_unlock(&driver_data->lock);
0068 
0069     return ret;
0070 }
0071 
0072 static int wm831x_wdt_stop(struct watchdog_device *wdt_dev)
0073 {
0074     struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
0075     struct wm831x *wm831x = driver_data->wm831x;
0076     int ret;
0077 
0078     mutex_lock(&driver_data->lock);
0079 
0080     ret = wm831x_reg_unlock(wm831x);
0081     if (ret == 0) {
0082         ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
0083                       WM831X_WDOG_ENA, 0);
0084         wm831x_reg_lock(wm831x);
0085     } else {
0086         dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
0087             ret);
0088     }
0089 
0090     mutex_unlock(&driver_data->lock);
0091 
0092     return ret;
0093 }
0094 
0095 static int wm831x_wdt_ping(struct watchdog_device *wdt_dev)
0096 {
0097     struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
0098     struct wm831x *wm831x = driver_data->wm831x;
0099     int ret;
0100     u16 reg;
0101 
0102     mutex_lock(&driver_data->lock);
0103 
0104     reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
0105 
0106     if (!(reg & WM831X_WDOG_RST_SRC)) {
0107         dev_err(wm831x->dev, "Hardware watchdog update unsupported\n");
0108         ret = -EINVAL;
0109         goto out;
0110     }
0111 
0112     reg |= WM831X_WDOG_RESET;
0113 
0114     ret = wm831x_reg_unlock(wm831x);
0115     if (ret == 0) {
0116         ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
0117         wm831x_reg_lock(wm831x);
0118     } else {
0119         dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
0120             ret);
0121     }
0122 
0123 out:
0124     mutex_unlock(&driver_data->lock);
0125 
0126     return ret;
0127 }
0128 
0129 static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev,
0130                   unsigned int timeout)
0131 {
0132     struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);
0133     struct wm831x *wm831x = driver_data->wm831x;
0134     int ret, i;
0135 
0136     for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
0137         if (wm831x_wdt_cfgs[i].time == timeout)
0138             break;
0139     if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
0140         return -EINVAL;
0141 
0142     ret = wm831x_reg_unlock(wm831x);
0143     if (ret == 0) {
0144         ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,
0145                       WM831X_WDOG_TO_MASK,
0146                       wm831x_wdt_cfgs[i].val);
0147         wm831x_reg_lock(wm831x);
0148     } else {
0149         dev_err(wm831x->dev, "Failed to unlock security key: %d\n",
0150             ret);
0151     }
0152 
0153     wdt_dev->timeout = timeout;
0154 
0155     return ret;
0156 }
0157 
0158 static const struct watchdog_info wm831x_wdt_info = {
0159     .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0160     .identity = "WM831x Watchdog",
0161 };
0162 
0163 static const struct watchdog_ops wm831x_wdt_ops = {
0164     .owner = THIS_MODULE,
0165     .start = wm831x_wdt_start,
0166     .stop = wm831x_wdt_stop,
0167     .ping = wm831x_wdt_ping,
0168     .set_timeout = wm831x_wdt_set_timeout,
0169 };
0170 
0171 static int wm831x_wdt_probe(struct platform_device *pdev)
0172 {
0173     struct device *dev = &pdev->dev;
0174     struct wm831x *wm831x = dev_get_drvdata(dev->parent);
0175     struct wm831x_pdata *chip_pdata = dev_get_platdata(dev->parent);
0176     struct wm831x_watchdog_pdata *pdata;
0177     struct wm831x_wdt_drvdata *driver_data;
0178     struct watchdog_device *wm831x_wdt;
0179     int reg, ret, i;
0180 
0181     ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
0182     if (ret < 0) {
0183         dev_err(wm831x->dev, "Failed to read watchdog status: %d\n",
0184             ret);
0185         return ret;
0186     }
0187     reg = ret;
0188 
0189     if (reg & WM831X_WDOG_DEBUG)
0190         dev_warn(wm831x->dev, "Watchdog is paused\n");
0191 
0192     driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
0193     if (!driver_data)
0194         return -ENOMEM;
0195 
0196     mutex_init(&driver_data->lock);
0197     driver_data->wm831x = wm831x;
0198 
0199     wm831x_wdt = &driver_data->wdt;
0200 
0201     wm831x_wdt->info = &wm831x_wdt_info;
0202     wm831x_wdt->ops = &wm831x_wdt_ops;
0203     wm831x_wdt->parent = dev;
0204     watchdog_set_nowayout(wm831x_wdt, nowayout);
0205     watchdog_set_drvdata(wm831x_wdt, driver_data);
0206 
0207     reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
0208     reg &= WM831X_WDOG_TO_MASK;
0209     for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)
0210         if (wm831x_wdt_cfgs[i].val == reg)
0211             break;
0212     if (i == ARRAY_SIZE(wm831x_wdt_cfgs))
0213         dev_warn(wm831x->dev,
0214              "Unknown watchdog timeout: %x\n", reg);
0215     else
0216         wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time;
0217 
0218     /* Apply any configuration */
0219     if (chip_pdata)
0220         pdata = chip_pdata->watchdog;
0221     else
0222         pdata = NULL;
0223 
0224     if (pdata) {
0225         reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK |
0226              WM831X_WDOG_RST_SRC);
0227 
0228         reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT;
0229         reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT;
0230         reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
0231 
0232         ret = wm831x_reg_unlock(wm831x);
0233         if (ret == 0) {
0234             ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
0235             wm831x_reg_lock(wm831x);
0236         } else {
0237             dev_err(wm831x->dev,
0238                 "Failed to unlock security key: %d\n", ret);
0239             return ret;
0240         }
0241     }
0242 
0243     return devm_watchdog_register_device(dev, &driver_data->wdt);
0244 }
0245 
0246 static struct platform_driver wm831x_wdt_driver = {
0247     .probe = wm831x_wdt_probe,
0248     .driver = {
0249         .name = "wm831x-watchdog",
0250     },
0251 };
0252 
0253 module_platform_driver(wm831x_wdt_driver);
0254 
0255 MODULE_AUTHOR("Mark Brown");
0256 MODULE_DESCRIPTION("WM831x Watchdog");
0257 MODULE_LICENSE("GPL");
0258 MODULE_ALIAS("platform:wm831x-watchdog");