1 /* 2 * Watchdog driver for the wm8350 3 * 4 * Copyright (C) 2007, 2008 Wolfson Microelectronics <linux@wolfsonmicro.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation 9 */ 10 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 13 #include <linux/module.h> 14 #include <linux/moduleparam.h> 15 #include <linux/types.h> 16 #include <linux/kernel.h> 17 #include <linux/platform_device.h> 18 #include <linux/watchdog.h> 19 #include <linux/uaccess.h> 20 #include <linux/mfd/wm8350/core.h> 21 22 static bool nowayout = WATCHDOG_NOWAYOUT; 23 module_param(nowayout, bool, 0); 24 MODULE_PARM_DESC(nowayout, 25 "Watchdog cannot be stopped once started (default=" 26 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 27 28 static DEFINE_MUTEX(wdt_mutex); 29 30 static struct { 31 unsigned int time; /* Seconds */ 32 u16 val; /* To be set in WM8350_SYSTEM_CONTROL_2 */ 33 } wm8350_wdt_cfgs[] = { 34 { 1, 0x02 }, 35 { 2, 0x04 }, 36 { 4, 0x05 }, 37 }; 38 39 static int wm8350_wdt_set_timeout(struct watchdog_device *wdt_dev, 40 unsigned int timeout) 41 { 42 struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev); 43 int ret, i; 44 u16 reg; 45 46 for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++) 47 if (wm8350_wdt_cfgs[i].time == timeout) 48 break; 49 if (i == ARRAY_SIZE(wm8350_wdt_cfgs)) 50 return -EINVAL; 51 52 mutex_lock(&wdt_mutex); 53 wm8350_reg_unlock(wm8350); 54 55 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2); 56 reg &= ~WM8350_WDOG_TO_MASK; 57 reg |= wm8350_wdt_cfgs[i].val; 58 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg); 59 60 wm8350_reg_lock(wm8350); 61 mutex_unlock(&wdt_mutex); 62 63 wdt_dev->timeout = timeout; 64 return ret; 65 } 66 67 static int wm8350_wdt_start(struct watchdog_device *wdt_dev) 68 { 69 struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev); 70 int ret; 71 u16 reg; 72 73 mutex_lock(&wdt_mutex); 74 wm8350_reg_unlock(wm8350); 75 76 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2); 77 reg &= ~WM8350_WDOG_MODE_MASK; 78 reg |= 0x20; 79 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg); 80 81 wm8350_reg_lock(wm8350); 82 mutex_unlock(&wdt_mutex); 83 84 return ret; 85 } 86 87 static int wm8350_wdt_stop(struct watchdog_device *wdt_dev) 88 { 89 struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev); 90 int ret; 91 u16 reg; 92 93 mutex_lock(&wdt_mutex); 94 wm8350_reg_unlock(wm8350); 95 96 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2); 97 reg &= ~WM8350_WDOG_MODE_MASK; 98 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg); 99 100 wm8350_reg_lock(wm8350); 101 mutex_unlock(&wdt_mutex); 102 103 return ret; 104 } 105 106 static int wm8350_wdt_ping(struct watchdog_device *wdt_dev) 107 { 108 struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev); 109 int ret; 110 u16 reg; 111 112 mutex_lock(&wdt_mutex); 113 114 reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2); 115 ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg); 116 117 mutex_unlock(&wdt_mutex); 118 119 return ret; 120 } 121 122 static const struct watchdog_info wm8350_wdt_info = { 123 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 124 .identity = "WM8350 Watchdog", 125 }; 126 127 static const struct watchdog_ops wm8350_wdt_ops = { 128 .owner = THIS_MODULE, 129 .start = wm8350_wdt_start, 130 .stop = wm8350_wdt_stop, 131 .ping = wm8350_wdt_ping, 132 .set_timeout = wm8350_wdt_set_timeout, 133 }; 134 135 static struct watchdog_device wm8350_wdt = { 136 .info = &wm8350_wdt_info, 137 .ops = &wm8350_wdt_ops, 138 .timeout = 4, 139 .min_timeout = 1, 140 .max_timeout = 4, 141 }; 142 143 static int __devinit wm8350_wdt_probe(struct platform_device *pdev) 144 { 145 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 146 147 if (!wm8350) { 148 pr_err("No driver data supplied\n"); 149 return -ENODEV; 150 } 151 152 watchdog_set_nowayout(&wm8350_wdt, nowayout); 153 watchdog_set_drvdata(&wm8350_wdt, wm8350); 154 155 /* Default to 4s timeout */ 156 wm8350_wdt_set_timeout(&wm8350_wdt, 4); 157 158 return watchdog_register_device(&wm8350_wdt); 159 } 160 161 static int __devexit wm8350_wdt_remove(struct platform_device *pdev) 162 { 163 watchdog_unregister_device(&wm8350_wdt); 164 return 0; 165 } 166 167 static struct platform_driver wm8350_wdt_driver = { 168 .probe = wm8350_wdt_probe, 169 .remove = __devexit_p(wm8350_wdt_remove), 170 .driver = { 171 .name = "wm8350-wdt", 172 }, 173 }; 174 175 module_platform_driver(wm8350_wdt_driver); 176 177 MODULE_AUTHOR("Mark Brown"); 178 MODULE_DESCRIPTION("WM8350 Watchdog"); 179 MODULE_LICENSE("GPL"); 180 MODULE_ALIAS("platform:wm8350-wdt"); 181