Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Watchdog driver for the wm8350
0004  *
0005  * Copyright (C) 2007, 2008 Wolfson Microelectronics <linux@wolfsonmicro.com>
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/types.h>
0013 #include <linux/kernel.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/watchdog.h>
0016 #include <linux/uaccess.h>
0017 #include <linux/mfd/wm8350/core.h>
0018 
0019 static bool nowayout = WATCHDOG_NOWAYOUT;
0020 module_param(nowayout, bool, 0);
0021 MODULE_PARM_DESC(nowayout,
0022          "Watchdog cannot be stopped once started (default="
0023          __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0024 
0025 static DEFINE_MUTEX(wdt_mutex);
0026 
0027 static struct {
0028     unsigned int time;  /* Seconds */
0029     u16 val;        /* To be set in WM8350_SYSTEM_CONTROL_2 */
0030 } wm8350_wdt_cfgs[] = {
0031     { 1, 0x02 },
0032     { 2, 0x04 },
0033     { 4, 0x05 },
0034 };
0035 
0036 static int wm8350_wdt_set_timeout(struct watchdog_device *wdt_dev,
0037                   unsigned int timeout)
0038 {
0039     struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
0040     int ret, i;
0041     u16 reg;
0042 
0043     for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
0044         if (wm8350_wdt_cfgs[i].time == timeout)
0045             break;
0046     if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
0047         return -EINVAL;
0048 
0049     mutex_lock(&wdt_mutex);
0050     wm8350_reg_unlock(wm8350);
0051 
0052     reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
0053     reg &= ~WM8350_WDOG_TO_MASK;
0054     reg |= wm8350_wdt_cfgs[i].val;
0055     ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
0056 
0057     wm8350_reg_lock(wm8350);
0058     mutex_unlock(&wdt_mutex);
0059 
0060     wdt_dev->timeout = timeout;
0061     return ret;
0062 }
0063 
0064 static int wm8350_wdt_start(struct watchdog_device *wdt_dev)
0065 {
0066     struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
0067     int ret;
0068     u16 reg;
0069 
0070     mutex_lock(&wdt_mutex);
0071     wm8350_reg_unlock(wm8350);
0072 
0073     reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
0074     reg &= ~WM8350_WDOG_MODE_MASK;
0075     reg |= 0x20;
0076     ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
0077 
0078     wm8350_reg_lock(wm8350);
0079     mutex_unlock(&wdt_mutex);
0080 
0081     return ret;
0082 }
0083 
0084 static int wm8350_wdt_stop(struct watchdog_device *wdt_dev)
0085 {
0086     struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
0087     int ret;
0088     u16 reg;
0089 
0090     mutex_lock(&wdt_mutex);
0091     wm8350_reg_unlock(wm8350);
0092 
0093     reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
0094     reg &= ~WM8350_WDOG_MODE_MASK;
0095     ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
0096 
0097     wm8350_reg_lock(wm8350);
0098     mutex_unlock(&wdt_mutex);
0099 
0100     return ret;
0101 }
0102 
0103 static int wm8350_wdt_ping(struct watchdog_device *wdt_dev)
0104 {
0105     struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
0106     int ret;
0107     u16 reg;
0108 
0109     mutex_lock(&wdt_mutex);
0110 
0111     reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
0112     ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
0113 
0114     mutex_unlock(&wdt_mutex);
0115 
0116     return ret;
0117 }
0118 
0119 static const struct watchdog_info wm8350_wdt_info = {
0120     .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0121     .identity = "WM8350 Watchdog",
0122 };
0123 
0124 static const struct watchdog_ops wm8350_wdt_ops = {
0125     .owner = THIS_MODULE,
0126     .start = wm8350_wdt_start,
0127     .stop = wm8350_wdt_stop,
0128     .ping = wm8350_wdt_ping,
0129     .set_timeout = wm8350_wdt_set_timeout,
0130 };
0131 
0132 static struct watchdog_device wm8350_wdt = {
0133     .info = &wm8350_wdt_info,
0134     .ops = &wm8350_wdt_ops,
0135     .timeout = 4,
0136     .min_timeout = 1,
0137     .max_timeout = 4,
0138 };
0139 
0140 static int wm8350_wdt_probe(struct platform_device *pdev)
0141 {
0142     struct wm8350 *wm8350 = platform_get_drvdata(pdev);
0143 
0144     if (!wm8350) {
0145         pr_err("No driver data supplied\n");
0146         return -ENODEV;
0147     }
0148 
0149     watchdog_set_nowayout(&wm8350_wdt, nowayout);
0150     watchdog_set_drvdata(&wm8350_wdt, wm8350);
0151     wm8350_wdt.parent = &pdev->dev;
0152 
0153     /* Default to 4s timeout */
0154     wm8350_wdt_set_timeout(&wm8350_wdt, 4);
0155 
0156     return watchdog_register_device(&wm8350_wdt);
0157 }
0158 
0159 static int wm8350_wdt_remove(struct platform_device *pdev)
0160 {
0161     watchdog_unregister_device(&wm8350_wdt);
0162     return 0;
0163 }
0164 
0165 static struct platform_driver wm8350_wdt_driver = {
0166     .probe = wm8350_wdt_probe,
0167     .remove = wm8350_wdt_remove,
0168     .driver = {
0169         .name = "wm8350-wdt",
0170     },
0171 };
0172 
0173 module_platform_driver(wm8350_wdt_driver);
0174 
0175 MODULE_AUTHOR("Mark Brown");
0176 MODULE_DESCRIPTION("WM8350 Watchdog");
0177 MODULE_LICENSE("GPL");
0178 MODULE_ALIAS("platform:wm8350-wdt");