xref: /linux/drivers/watchdog/wm831x_wdt.c (revision 3f9d5133)
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 
21 static bool nowayout = WATCHDOG_NOWAYOUT;
22 module_param(nowayout, bool, 0);
23 MODULE_PARM_DESC(nowayout,
24 		 "Watchdog cannot be stopped once started (default="
25 		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
26 
27 struct 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.  */
36 static 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 
wm831x_wdt_start(struct watchdog_device * wdt_dev)49 static 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 
wm831x_wdt_stop(struct watchdog_device * wdt_dev)72 static 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 
wm831x_wdt_ping(struct watchdog_device * wdt_dev)95 static 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 
123 out:
124 	mutex_unlock(&driver_data->lock);
125 
126 	return ret;
127 }
128 
wm831x_wdt_set_timeout(struct watchdog_device * wdt_dev,unsigned int timeout)129 static 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 
158 static const struct watchdog_info wm831x_wdt_info = {
159 	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
160 	.identity = "WM831x Watchdog",
161 };
162 
163 static 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 
wm831x_wdt_probe(struct platform_device * pdev)171 static 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 
246 static struct platform_driver wm831x_wdt_driver = {
247 	.probe = wm831x_wdt_probe,
248 	.driver = {
249 		.name = "wm831x-watchdog",
250 	},
251 };
252 
253 module_platform_driver(wm831x_wdt_driver);
254 
255 MODULE_AUTHOR("Mark Brown");
256 MODULE_DESCRIPTION("WM831x Watchdog");
257 MODULE_LICENSE("GPL");
258 MODULE_ALIAS("platform:wm831x-watchdog");
259