Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Kontron PLD watchdog driver
  4 *
  5 * Copyright (c) 2010-2013 Kontron Europe GmbH
  6 * Author: Michael Brunner <michael.brunner@kontron.com>
  7 *
  8 * Note: From the PLD watchdog point of view timeout and pretimeout are
  9 *       defined differently than in the kernel.
 10 *       First the pretimeout stage runs out before the timeout stage gets
 11 *       active.
 12 *
 13 * Kernel/API:                     P-----| pretimeout
 14 *               |-----------------------T timeout
 15 * Watchdog:     |-----------------P       pretimeout_stage
 16 *                                 |-----T timeout_stage
 17 */
 18
 19#include <linux/module.h>
 20#include <linux/moduleparam.h>
 21#include <linux/uaccess.h>
 22#include <linux/watchdog.h>
 23#include <linux/platform_device.h>
 24#include <linux/mfd/kempld.h>
 25
 26#define KEMPLD_WDT_STAGE_TIMEOUT(x)	(0x1b + (x) * 4)
 27#define KEMPLD_WDT_STAGE_CFG(x)		(0x18 + (x))
 28#define STAGE_CFG_GET_PRESCALER(x)	(((x) & 0x30) >> 4)
 29#define STAGE_CFG_SET_PRESCALER(x)	(((x) & 0x3) << 4)
 30#define STAGE_CFG_PRESCALER_MASK	0x30
 31#define STAGE_CFG_ACTION_MASK		0x7
 32#define STAGE_CFG_ASSERT		(1 << 3)
 33
 34#define KEMPLD_WDT_MAX_STAGES		2
 35#define KEMPLD_WDT_KICK			0x16
 36#define KEMPLD_WDT_CFG			0x17
 37#define KEMPLD_WDT_CFG_ENABLE		0x10
 38#define KEMPLD_WDT_CFG_ENABLE_LOCK	0x8
 39#define KEMPLD_WDT_CFG_GLOBAL_LOCK	0x80
 40
 41enum {
 42	ACTION_NONE = 0,
 43	ACTION_RESET,
 44	ACTION_NMI,
 45	ACTION_SMI,
 46	ACTION_SCI,
 47	ACTION_DELAY,
 48};
 49
 50enum {
 51	STAGE_TIMEOUT = 0,
 52	STAGE_PRETIMEOUT,
 53};
 54
 55enum {
 56	PRESCALER_21 = 0,
 57	PRESCALER_17,
 58	PRESCALER_12,
 59};
 60
 61static const u32 kempld_prescaler[] = {
 62	[PRESCALER_21] = (1 << 21) - 1,
 63	[PRESCALER_17] = (1 << 17) - 1,
 64	[PRESCALER_12] = (1 << 12) - 1,
 65	0,
 66};
 67
 68struct kempld_wdt_stage {
 69	unsigned int	id;
 70	u32		mask;
 71};
 72
 73struct kempld_wdt_data {
 74	struct kempld_device_data	*pld;
 75	struct watchdog_device		wdd;
 76	unsigned int			pretimeout;
 77	struct kempld_wdt_stage		stage[KEMPLD_WDT_MAX_STAGES];
 78#ifdef CONFIG_PM
 79	u8				pm_status_store;
 80#endif
 81};
 82
 83#define DEFAULT_TIMEOUT		30 /* seconds */
 84#define DEFAULT_PRETIMEOUT	0
 85
 86static unsigned int timeout = DEFAULT_TIMEOUT;
 87module_param(timeout, uint, 0);
 88MODULE_PARM_DESC(timeout,
 89	"Watchdog timeout in seconds. (>=0, default="
 90	__MODULE_STRING(DEFAULT_TIMEOUT) ")");
 91
 92static unsigned int pretimeout = DEFAULT_PRETIMEOUT;
 93module_param(pretimeout, uint, 0);
 94MODULE_PARM_DESC(pretimeout,
 95	"Watchdog pretimeout in seconds. (>=0, default="
 96	__MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
 97
 98static bool nowayout = WATCHDOG_NOWAYOUT;
 99module_param(nowayout, bool, 0);
100MODULE_PARM_DESC(nowayout,
101	"Watchdog cannot be stopped once started (default="
102	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
103
104static int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data,
105					struct kempld_wdt_stage *stage,
106					u8 action)
107{
108	struct kempld_device_data *pld = wdt_data->pld;
109	u8 stage_cfg;
110
111	if (!stage || !stage->mask)
112		return -EINVAL;
113
114	kempld_get_mutex(pld);
115	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
116	stage_cfg &= ~STAGE_CFG_ACTION_MASK;
117	stage_cfg |= (action & STAGE_CFG_ACTION_MASK);
118
119	if (action == ACTION_RESET)
120		stage_cfg |= STAGE_CFG_ASSERT;
121	else
122		stage_cfg &= ~STAGE_CFG_ASSERT;
123
124	kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
125	kempld_release_mutex(pld);
126
127	return 0;
128}
129
130static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
131					struct kempld_wdt_stage *stage,
132					unsigned int timeout)
133{
134	struct kempld_device_data *pld = wdt_data->pld;
135	u32 prescaler;
136	u64 stage_timeout64;
137	u32 stage_timeout;
138	u32 remainder;
139	u8 stage_cfg;
140
141	prescaler = kempld_prescaler[PRESCALER_21];
142
143	if (!stage)
144		return -EINVAL;
145
146	stage_timeout64 = (u64)timeout * pld->pld_clock;
147	remainder = do_div(stage_timeout64, prescaler);
148	if (remainder)
149		stage_timeout64++;
150
151	if (stage_timeout64 > stage->mask)
152		return -EINVAL;
153
154	stage_timeout = stage_timeout64 & stage->mask;
155
156	kempld_get_mutex(pld);
157	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
158	stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
159	stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);
160	kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
161	kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
162			stage_timeout);
163	kempld_release_mutex(pld);
164
165	return 0;
166}
167
168/*
169 * kempld_get_mutex must be called prior to calling this function.
170 */
171static unsigned int kempld_wdt_get_timeout(struct kempld_wdt_data *wdt_data,
172						struct kempld_wdt_stage *stage)
173{
174	struct kempld_device_data *pld = wdt_data->pld;
175	unsigned int timeout;
176	u64 stage_timeout;
177	u32 prescaler;
178	u32 remainder;
179	u8 stage_cfg;
180
181	if (!stage->mask)
182		return 0;
183
184	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
185	stage_timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id));
186	prescaler = kempld_prescaler[STAGE_CFG_GET_PRESCALER(stage_cfg)];
187
188	stage_timeout = (stage_timeout & stage->mask) * prescaler;
189	remainder = do_div(stage_timeout, pld->pld_clock);
190	if (remainder)
191		stage_timeout++;
192
193	timeout = stage_timeout;
194	WARN_ON_ONCE(timeout != stage_timeout);
195
196	return timeout;
197}
198
199static int kempld_wdt_set_timeout(struct watchdog_device *wdd,
200					unsigned int timeout)
201{
202	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
203	struct kempld_wdt_stage *pretimeout_stage;
204	struct kempld_wdt_stage *timeout_stage;
205	int ret;
206
207	timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
208	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
209
210	if (pretimeout_stage->mask && wdt_data->pretimeout > 0)
211		timeout = wdt_data->pretimeout;
212
213	ret = kempld_wdt_set_stage_action(wdt_data, timeout_stage,
214						ACTION_RESET);
215	if (ret)
216		return ret;
217	ret = kempld_wdt_set_stage_timeout(wdt_data, timeout_stage,
218						timeout);
219	if (ret)
220		return ret;
221
222	wdd->timeout = timeout;
223	return 0;
224}
225
226static int kempld_wdt_set_pretimeout(struct watchdog_device *wdd,
227					unsigned int pretimeout)
228{
229	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
230	struct kempld_wdt_stage *pretimeout_stage;
231	u8 action = ACTION_NONE;
232	int ret;
233
234	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
235
236	if (!pretimeout_stage->mask)
237		return -ENXIO;
238
239	if (pretimeout > wdd->timeout)
240		return -EINVAL;
241
242	if (pretimeout > 0)
243		action = ACTION_NMI;
244
245	ret = kempld_wdt_set_stage_action(wdt_data, pretimeout_stage,
246						action);
247	if (ret)
248		return ret;
249	ret = kempld_wdt_set_stage_timeout(wdt_data, pretimeout_stage,
250						wdd->timeout - pretimeout);
251	if (ret)
252		return ret;
253
254	wdt_data->pretimeout = pretimeout;
255	return 0;
256}
257
258static void kempld_wdt_update_timeouts(struct kempld_wdt_data *wdt_data)
259{
260	struct kempld_device_data *pld = wdt_data->pld;
261	struct kempld_wdt_stage *pretimeout_stage;
262	struct kempld_wdt_stage *timeout_stage;
263	unsigned int pretimeout, timeout;
264
265	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
266	timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
267
268	kempld_get_mutex(pld);
269	pretimeout = kempld_wdt_get_timeout(wdt_data, pretimeout_stage);
270	timeout = kempld_wdt_get_timeout(wdt_data, timeout_stage);
271	kempld_release_mutex(pld);
272
273	if (pretimeout)
274		wdt_data->pretimeout = timeout;
275	else
276		wdt_data->pretimeout = 0;
277
278	wdt_data->wdd.timeout = pretimeout + timeout;
279}
280
281static int kempld_wdt_start(struct watchdog_device *wdd)
282{
283	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
284	struct kempld_device_data *pld = wdt_data->pld;
285	u8 status;
286	int ret;
287
288	ret = kempld_wdt_set_timeout(wdd, wdd->timeout);
289	if (ret)
290		return ret;
291
292	kempld_get_mutex(pld);
293	status = kempld_read8(pld, KEMPLD_WDT_CFG);
294	status |= KEMPLD_WDT_CFG_ENABLE;
295	kempld_write8(pld, KEMPLD_WDT_CFG, status);
296	status = kempld_read8(pld, KEMPLD_WDT_CFG);
297	kempld_release_mutex(pld);
298
299	/* Check if the watchdog was enabled */
300	if (!(status & KEMPLD_WDT_CFG_ENABLE))
301		return -EACCES;
302
303	return 0;
304}
305
306static int kempld_wdt_stop(struct watchdog_device *wdd)
307{
308	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
309	struct kempld_device_data *pld = wdt_data->pld;
310	u8 status;
311
312	kempld_get_mutex(pld);
313	status = kempld_read8(pld, KEMPLD_WDT_CFG);
314	status &= ~KEMPLD_WDT_CFG_ENABLE;
315	kempld_write8(pld, KEMPLD_WDT_CFG, status);
316	status = kempld_read8(pld, KEMPLD_WDT_CFG);
317	kempld_release_mutex(pld);
318
319	/* Check if the watchdog was disabled */
320	if (status & KEMPLD_WDT_CFG_ENABLE)
321		return -EACCES;
322
323	return 0;
324}
325
326static int kempld_wdt_keepalive(struct watchdog_device *wdd)
327{
328	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
329	struct kempld_device_data *pld = wdt_data->pld;
330
331	kempld_get_mutex(pld);
332	kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
333	kempld_release_mutex(pld);
334
335	return 0;
336}
337
338static long kempld_wdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
339				unsigned long arg)
340{
341	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
342	void __user *argp = (void __user *)arg;
343	int ret = -ENOIOCTLCMD;
344	int __user *p = argp;
345	int new_value;
346
347	switch (cmd) {
348	case WDIOC_SETPRETIMEOUT:
349		if (get_user(new_value, p))
350			return -EFAULT;
351		ret = kempld_wdt_set_pretimeout(wdd, new_value);
352		if (ret)
353			return ret;
354		ret = kempld_wdt_keepalive(wdd);
355		break;
356	case WDIOC_GETPRETIMEOUT:
357		ret = put_user(wdt_data->pretimeout, (int __user *)arg);
358		break;
359	}
360
361	return ret;
362}
363
364static int kempld_wdt_probe_stages(struct watchdog_device *wdd)
365{
366	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
367	struct kempld_device_data *pld = wdt_data->pld;
368	struct kempld_wdt_stage *pretimeout_stage;
369	struct kempld_wdt_stage *timeout_stage;
370	u8 index, data, data_orig;
371	u32 mask;
372	int i, j;
373
374	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
375	timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
376
377	pretimeout_stage->mask = 0;
378	timeout_stage->mask = 0;
379
380	for (i = 0; i < 3; i++) {
381		index = KEMPLD_WDT_STAGE_TIMEOUT(i);
382		mask = 0;
383
384		kempld_get_mutex(pld);
385		/* Probe each byte individually. */
386		for (j = 0; j < 4; j++) {
387			data_orig = kempld_read8(pld, index + j);
388			kempld_write8(pld, index + j, 0x00);
389			data = kempld_read8(pld, index + j);
390			/* A failed write means this byte is reserved */
391			if (data != 0x00)
392				break;
393			kempld_write8(pld, index + j, data_orig);
394			mask |= 0xff << (j * 8);
395		}
396		kempld_release_mutex(pld);
397
398		/* Assign available stages to timeout and pretimeout */
399		if (!timeout_stage->mask) {
400			timeout_stage->mask = mask;
401			timeout_stage->id = i;
402		} else {
403			if (pld->feature_mask & KEMPLD_FEATURE_BIT_NMI) {
404				pretimeout_stage->mask = timeout_stage->mask;
405				timeout_stage->mask = mask;
406				pretimeout_stage->id = timeout_stage->id;
407				timeout_stage->id = i;
408			}
409			break;
410		}
411	}
412
413	if (!timeout_stage->mask)
414		return -ENODEV;
415
416	return 0;
417}
418
419static const struct watchdog_info kempld_wdt_info = {
420	.identity	= "KEMPLD Watchdog",
421	.options	= WDIOF_SETTIMEOUT |
422			WDIOF_KEEPALIVEPING |
423			WDIOF_MAGICCLOSE |
424			WDIOF_PRETIMEOUT
425};
426
427static const struct watchdog_ops kempld_wdt_ops = {
428	.owner		= THIS_MODULE,
429	.start		= kempld_wdt_start,
430	.stop		= kempld_wdt_stop,
431	.ping		= kempld_wdt_keepalive,
432	.set_timeout	= kempld_wdt_set_timeout,
433	.ioctl		= kempld_wdt_ioctl,
434};
435
436static int kempld_wdt_probe(struct platform_device *pdev)
437{
438	struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
439	struct kempld_wdt_data *wdt_data;
440	struct device *dev = &pdev->dev;
441	struct watchdog_device *wdd;
442	u8 status;
443	int ret = 0;
444
445	wdt_data = devm_kzalloc(dev, sizeof(*wdt_data), GFP_KERNEL);
446	if (!wdt_data)
447		return -ENOMEM;
448
449	wdt_data->pld = pld;
450	wdd = &wdt_data->wdd;
451	wdd->parent = dev;
452
453	kempld_get_mutex(pld);
454	status = kempld_read8(pld, KEMPLD_WDT_CFG);
455	kempld_release_mutex(pld);
456
457	/* Enable nowayout if watchdog is already locked */
458	if (status & (KEMPLD_WDT_CFG_ENABLE_LOCK |
459			KEMPLD_WDT_CFG_GLOBAL_LOCK)) {
460		if (!nowayout)
461			dev_warn(dev,
462				 "Forcing nowayout - watchdog lock enabled!\n");
463		nowayout = true;
464	}
465
466	wdd->info = &kempld_wdt_info;
467	wdd->ops = &kempld_wdt_ops;
468
469	watchdog_set_drvdata(wdd, wdt_data);
470	watchdog_set_nowayout(wdd, nowayout);
471
472	ret = kempld_wdt_probe_stages(wdd);
473	if (ret)
474		return ret;
475
476	kempld_wdt_set_timeout(wdd, timeout);
477	kempld_wdt_set_pretimeout(wdd, pretimeout);
478
479	/* Check if watchdog is already enabled */
480	if (status & KEMPLD_WDT_CFG_ENABLE) {
481		/* Get current watchdog settings */
482		kempld_wdt_update_timeouts(wdt_data);
483		dev_info(dev, "Watchdog was already enabled\n");
484	}
485
486	platform_set_drvdata(pdev, wdt_data);
487	watchdog_stop_on_reboot(wdd);
488	watchdog_stop_on_unregister(wdd);
489	ret = devm_watchdog_register_device(dev, wdd);
490	if (ret)
491		return ret;
492
493	dev_info(dev, "Watchdog registered with %ds timeout\n", wdd->timeout);
494
495	return 0;
496}
497
498#ifdef CONFIG_PM
499/* Disable watchdog if it is active during suspend */
500static int kempld_wdt_suspend(struct platform_device *pdev,
501				pm_message_t message)
502{
503	struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
504	struct kempld_device_data *pld = wdt_data->pld;
505	struct watchdog_device *wdd = &wdt_data->wdd;
506
507	kempld_get_mutex(pld);
508	wdt_data->pm_status_store = kempld_read8(pld, KEMPLD_WDT_CFG);
509	kempld_release_mutex(pld);
510
511	kempld_wdt_update_timeouts(wdt_data);
512
513	if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
514		return kempld_wdt_stop(wdd);
515
516	return 0;
517}
518
519/* Enable watchdog and configure it if necessary */
520static int kempld_wdt_resume(struct platform_device *pdev)
521{
522	struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
523	struct watchdog_device *wdd = &wdt_data->wdd;
524
525	/*
526	 * If watchdog was stopped before suspend be sure it gets disabled
527	 * again, for the case BIOS has enabled it during resume
528	 */
529	if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
530		return kempld_wdt_start(wdd);
531	else
532		return kempld_wdt_stop(wdd);
533}
534#else
535#define kempld_wdt_suspend	NULL
536#define kempld_wdt_resume	NULL
537#endif
538
539static struct platform_driver kempld_wdt_driver = {
540	.driver		= {
541		.name	= "kempld-wdt",
542	},
543	.probe		= kempld_wdt_probe,
544	.suspend	= kempld_wdt_suspend,
545	.resume		= kempld_wdt_resume,
546};
547
548module_platform_driver(kempld_wdt_driver);
549
550MODULE_DESCRIPTION("KEM PLD Watchdog Driver");
551MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
552MODULE_LICENSE("GPL");
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Kontron PLD watchdog driver
  4 *
  5 * Copyright (c) 2010-2013 Kontron Europe GmbH
  6 * Author: Michael Brunner <michael.brunner@kontron.com>
  7 *
  8 * Note: From the PLD watchdog point of view timeout and pretimeout are
  9 *       defined differently than in the kernel.
 10 *       First the pretimeout stage runs out before the timeout stage gets
 11 *       active.
 12 *
 13 * Kernel/API:                     P-----| pretimeout
 14 *               |-----------------------T timeout
 15 * Watchdog:     |-----------------P       pretimeout_stage
 16 *                                 |-----T timeout_stage
 17 */
 18
 19#include <linux/module.h>
 20#include <linux/moduleparam.h>
 21#include <linux/uaccess.h>
 22#include <linux/watchdog.h>
 23#include <linux/platform_device.h>
 24#include <linux/mfd/kempld.h>
 25
 26#define KEMPLD_WDT_STAGE_TIMEOUT(x)	(0x1b + (x) * 4)
 27#define KEMPLD_WDT_STAGE_CFG(x)		(0x18 + (x))
 28#define STAGE_CFG_GET_PRESCALER(x)	(((x) & 0x30) >> 4)
 29#define STAGE_CFG_SET_PRESCALER(x)	(((x) & 0x3) << 4)
 30#define STAGE_CFG_PRESCALER_MASK	0x30
 31#define STAGE_CFG_ACTION_MASK		0x7
 32#define STAGE_CFG_ASSERT		(1 << 3)
 33
 34#define KEMPLD_WDT_MAX_STAGES		2
 35#define KEMPLD_WDT_KICK			0x16
 36#define KEMPLD_WDT_CFG			0x17
 37#define KEMPLD_WDT_CFG_ENABLE		0x10
 38#define KEMPLD_WDT_CFG_ENABLE_LOCK	0x8
 39#define KEMPLD_WDT_CFG_GLOBAL_LOCK	0x80
 40
 41enum {
 42	ACTION_NONE = 0,
 43	ACTION_RESET,
 44	ACTION_NMI,
 45	ACTION_SMI,
 46	ACTION_SCI,
 47	ACTION_DELAY,
 48};
 49
 50enum {
 51	STAGE_TIMEOUT = 0,
 52	STAGE_PRETIMEOUT,
 53};
 54
 55enum {
 56	PRESCALER_21 = 0,
 57	PRESCALER_17,
 58	PRESCALER_12,
 59};
 60
 61static const u32 kempld_prescaler[] = {
 62	[PRESCALER_21] = (1 << 21) - 1,
 63	[PRESCALER_17] = (1 << 17) - 1,
 64	[PRESCALER_12] = (1 << 12) - 1,
 65	0,
 66};
 67
 68struct kempld_wdt_stage {
 69	unsigned int	id;
 70	u32		mask;
 71};
 72
 73struct kempld_wdt_data {
 74	struct kempld_device_data	*pld;
 75	struct watchdog_device		wdd;
 76	unsigned int			pretimeout;
 77	struct kempld_wdt_stage		stage[KEMPLD_WDT_MAX_STAGES];
 
 78	u8				pm_status_store;
 
 79};
 80
 81#define DEFAULT_TIMEOUT		30 /* seconds */
 82#define DEFAULT_PRETIMEOUT	0
 83
 84static unsigned int timeout = DEFAULT_TIMEOUT;
 85module_param(timeout, uint, 0);
 86MODULE_PARM_DESC(timeout,
 87	"Watchdog timeout in seconds. (>=0, default="
 88	__MODULE_STRING(DEFAULT_TIMEOUT) ")");
 89
 90static unsigned int pretimeout = DEFAULT_PRETIMEOUT;
 91module_param(pretimeout, uint, 0);
 92MODULE_PARM_DESC(pretimeout,
 93	"Watchdog pretimeout in seconds. (>=0, default="
 94	__MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
 95
 96static bool nowayout = WATCHDOG_NOWAYOUT;
 97module_param(nowayout, bool, 0);
 98MODULE_PARM_DESC(nowayout,
 99	"Watchdog cannot be stopped once started (default="
100	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
101
102static int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data,
103					struct kempld_wdt_stage *stage,
104					u8 action)
105{
106	struct kempld_device_data *pld = wdt_data->pld;
107	u8 stage_cfg;
108
109	if (!stage || !stage->mask)
110		return -EINVAL;
111
112	kempld_get_mutex(pld);
113	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
114	stage_cfg &= ~STAGE_CFG_ACTION_MASK;
115	stage_cfg |= (action & STAGE_CFG_ACTION_MASK);
116
117	if (action == ACTION_RESET)
118		stage_cfg |= STAGE_CFG_ASSERT;
119	else
120		stage_cfg &= ~STAGE_CFG_ASSERT;
121
122	kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
123	kempld_release_mutex(pld);
124
125	return 0;
126}
127
128static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
129					struct kempld_wdt_stage *stage,
130					unsigned int timeout)
131{
132	struct kempld_device_data *pld = wdt_data->pld;
133	u32 prescaler;
134	u64 stage_timeout64;
135	u32 stage_timeout;
136	u32 remainder;
137	u8 stage_cfg;
138
139	prescaler = kempld_prescaler[PRESCALER_21];
140
141	if (!stage)
142		return -EINVAL;
143
144	stage_timeout64 = (u64)timeout * pld->pld_clock;
145	remainder = do_div(stage_timeout64, prescaler);
146	if (remainder)
147		stage_timeout64++;
148
149	if (stage_timeout64 > stage->mask)
150		return -EINVAL;
151
152	stage_timeout = stage_timeout64 & stage->mask;
153
154	kempld_get_mutex(pld);
155	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
156	stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
157	stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);
158	kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
159	kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
160			stage_timeout);
161	kempld_release_mutex(pld);
162
163	return 0;
164}
165
166/*
167 * kempld_get_mutex must be called prior to calling this function.
168 */
169static unsigned int kempld_wdt_get_timeout(struct kempld_wdt_data *wdt_data,
170						struct kempld_wdt_stage *stage)
171{
172	struct kempld_device_data *pld = wdt_data->pld;
173	unsigned int timeout;
174	u64 stage_timeout;
175	u32 prescaler;
176	u32 remainder;
177	u8 stage_cfg;
178
179	if (!stage->mask)
180		return 0;
181
182	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
183	stage_timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id));
184	prescaler = kempld_prescaler[STAGE_CFG_GET_PRESCALER(stage_cfg)];
185
186	stage_timeout = (stage_timeout & stage->mask) * prescaler;
187	remainder = do_div(stage_timeout, pld->pld_clock);
188	if (remainder)
189		stage_timeout++;
190
191	timeout = stage_timeout;
192	WARN_ON_ONCE(timeout != stage_timeout);
193
194	return timeout;
195}
196
197static int kempld_wdt_set_timeout(struct watchdog_device *wdd,
198					unsigned int timeout)
199{
200	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
201	struct kempld_wdt_stage *pretimeout_stage;
202	struct kempld_wdt_stage *timeout_stage;
203	int ret;
204
205	timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
206	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
207
208	if (pretimeout_stage->mask && wdt_data->pretimeout > 0)
209		timeout = wdt_data->pretimeout;
210
211	ret = kempld_wdt_set_stage_action(wdt_data, timeout_stage,
212						ACTION_RESET);
213	if (ret)
214		return ret;
215	ret = kempld_wdt_set_stage_timeout(wdt_data, timeout_stage,
216						timeout);
217	if (ret)
218		return ret;
219
220	wdd->timeout = timeout;
221	return 0;
222}
223
224static int kempld_wdt_set_pretimeout(struct watchdog_device *wdd,
225					unsigned int pretimeout)
226{
227	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
228	struct kempld_wdt_stage *pretimeout_stage;
229	u8 action = ACTION_NONE;
230	int ret;
231
232	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
233
234	if (!pretimeout_stage->mask)
235		return -ENXIO;
236
237	if (pretimeout > wdd->timeout)
238		return -EINVAL;
239
240	if (pretimeout > 0)
241		action = ACTION_NMI;
242
243	ret = kempld_wdt_set_stage_action(wdt_data, pretimeout_stage,
244						action);
245	if (ret)
246		return ret;
247	ret = kempld_wdt_set_stage_timeout(wdt_data, pretimeout_stage,
248						wdd->timeout - pretimeout);
249	if (ret)
250		return ret;
251
252	wdt_data->pretimeout = pretimeout;
253	return 0;
254}
255
256static void kempld_wdt_update_timeouts(struct kempld_wdt_data *wdt_data)
257{
258	struct kempld_device_data *pld = wdt_data->pld;
259	struct kempld_wdt_stage *pretimeout_stage;
260	struct kempld_wdt_stage *timeout_stage;
261	unsigned int pretimeout, timeout;
262
263	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
264	timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
265
266	kempld_get_mutex(pld);
267	pretimeout = kempld_wdt_get_timeout(wdt_data, pretimeout_stage);
268	timeout = kempld_wdt_get_timeout(wdt_data, timeout_stage);
269	kempld_release_mutex(pld);
270
271	if (pretimeout)
272		wdt_data->pretimeout = timeout;
273	else
274		wdt_data->pretimeout = 0;
275
276	wdt_data->wdd.timeout = pretimeout + timeout;
277}
278
279static int kempld_wdt_start(struct watchdog_device *wdd)
280{
281	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
282	struct kempld_device_data *pld = wdt_data->pld;
283	u8 status;
284	int ret;
285
286	ret = kempld_wdt_set_timeout(wdd, wdd->timeout);
287	if (ret)
288		return ret;
289
290	kempld_get_mutex(pld);
291	status = kempld_read8(pld, KEMPLD_WDT_CFG);
292	status |= KEMPLD_WDT_CFG_ENABLE;
293	kempld_write8(pld, KEMPLD_WDT_CFG, status);
294	status = kempld_read8(pld, KEMPLD_WDT_CFG);
295	kempld_release_mutex(pld);
296
297	/* Check if the watchdog was enabled */
298	if (!(status & KEMPLD_WDT_CFG_ENABLE))
299		return -EACCES;
300
301	return 0;
302}
303
304static int kempld_wdt_stop(struct watchdog_device *wdd)
305{
306	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
307	struct kempld_device_data *pld = wdt_data->pld;
308	u8 status;
309
310	kempld_get_mutex(pld);
311	status = kempld_read8(pld, KEMPLD_WDT_CFG);
312	status &= ~KEMPLD_WDT_CFG_ENABLE;
313	kempld_write8(pld, KEMPLD_WDT_CFG, status);
314	status = kempld_read8(pld, KEMPLD_WDT_CFG);
315	kempld_release_mutex(pld);
316
317	/* Check if the watchdog was disabled */
318	if (status & KEMPLD_WDT_CFG_ENABLE)
319		return -EACCES;
320
321	return 0;
322}
323
324static int kempld_wdt_keepalive(struct watchdog_device *wdd)
325{
326	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
327	struct kempld_device_data *pld = wdt_data->pld;
328
329	kempld_get_mutex(pld);
330	kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
331	kempld_release_mutex(pld);
332
333	return 0;
334}
335
336static long kempld_wdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
337				unsigned long arg)
338{
339	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
340	void __user *argp = (void __user *)arg;
341	int ret = -ENOIOCTLCMD;
342	int __user *p = argp;
343	int new_value;
344
345	switch (cmd) {
346	case WDIOC_SETPRETIMEOUT:
347		if (get_user(new_value, p))
348			return -EFAULT;
349		ret = kempld_wdt_set_pretimeout(wdd, new_value);
350		if (ret)
351			return ret;
352		ret = kempld_wdt_keepalive(wdd);
353		break;
354	case WDIOC_GETPRETIMEOUT:
355		ret = put_user(wdt_data->pretimeout, (int __user *)arg);
356		break;
357	}
358
359	return ret;
360}
361
362static int kempld_wdt_probe_stages(struct watchdog_device *wdd)
363{
364	struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
365	struct kempld_device_data *pld = wdt_data->pld;
366	struct kempld_wdt_stage *pretimeout_stage;
367	struct kempld_wdt_stage *timeout_stage;
368	u8 index, data, data_orig;
369	u32 mask;
370	int i, j;
371
372	pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
373	timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
374
375	pretimeout_stage->mask = 0;
376	timeout_stage->mask = 0;
377
378	for (i = 0; i < 3; i++) {
379		index = KEMPLD_WDT_STAGE_TIMEOUT(i);
380		mask = 0;
381
382		kempld_get_mutex(pld);
383		/* Probe each byte individually. */
384		for (j = 0; j < 4; j++) {
385			data_orig = kempld_read8(pld, index + j);
386			kempld_write8(pld, index + j, 0x00);
387			data = kempld_read8(pld, index + j);
388			/* A failed write means this byte is reserved */
389			if (data != 0x00)
390				break;
391			kempld_write8(pld, index + j, data_orig);
392			mask |= 0xff << (j * 8);
393		}
394		kempld_release_mutex(pld);
395
396		/* Assign available stages to timeout and pretimeout */
397		if (!timeout_stage->mask) {
398			timeout_stage->mask = mask;
399			timeout_stage->id = i;
400		} else {
401			if (pld->feature_mask & KEMPLD_FEATURE_BIT_NMI) {
402				pretimeout_stage->mask = timeout_stage->mask;
403				timeout_stage->mask = mask;
404				pretimeout_stage->id = timeout_stage->id;
405				timeout_stage->id = i;
406			}
407			break;
408		}
409	}
410
411	if (!timeout_stage->mask)
412		return -ENODEV;
413
414	return 0;
415}
416
417static const struct watchdog_info kempld_wdt_info = {
418	.identity	= "KEMPLD Watchdog",
419	.options	= WDIOF_SETTIMEOUT |
420			WDIOF_KEEPALIVEPING |
421			WDIOF_MAGICCLOSE |
422			WDIOF_PRETIMEOUT
423};
424
425static const struct watchdog_ops kempld_wdt_ops = {
426	.owner		= THIS_MODULE,
427	.start		= kempld_wdt_start,
428	.stop		= kempld_wdt_stop,
429	.ping		= kempld_wdt_keepalive,
430	.set_timeout	= kempld_wdt_set_timeout,
431	.ioctl		= kempld_wdt_ioctl,
432};
433
434static int kempld_wdt_probe(struct platform_device *pdev)
435{
436	struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
437	struct kempld_wdt_data *wdt_data;
438	struct device *dev = &pdev->dev;
439	struct watchdog_device *wdd;
440	u8 status;
441	int ret = 0;
442
443	wdt_data = devm_kzalloc(dev, sizeof(*wdt_data), GFP_KERNEL);
444	if (!wdt_data)
445		return -ENOMEM;
446
447	wdt_data->pld = pld;
448	wdd = &wdt_data->wdd;
449	wdd->parent = dev;
450
451	kempld_get_mutex(pld);
452	status = kempld_read8(pld, KEMPLD_WDT_CFG);
453	kempld_release_mutex(pld);
454
455	/* Enable nowayout if watchdog is already locked */
456	if (status & (KEMPLD_WDT_CFG_ENABLE_LOCK |
457			KEMPLD_WDT_CFG_GLOBAL_LOCK)) {
458		if (!nowayout)
459			dev_warn(dev,
460				 "Forcing nowayout - watchdog lock enabled!\n");
461		nowayout = true;
462	}
463
464	wdd->info = &kempld_wdt_info;
465	wdd->ops = &kempld_wdt_ops;
466
467	watchdog_set_drvdata(wdd, wdt_data);
468	watchdog_set_nowayout(wdd, nowayout);
469
470	ret = kempld_wdt_probe_stages(wdd);
471	if (ret)
472		return ret;
473
474	kempld_wdt_set_timeout(wdd, timeout);
475	kempld_wdt_set_pretimeout(wdd, pretimeout);
476
477	/* Check if watchdog is already enabled */
478	if (status & KEMPLD_WDT_CFG_ENABLE) {
479		/* Get current watchdog settings */
480		kempld_wdt_update_timeouts(wdt_data);
481		dev_info(dev, "Watchdog was already enabled\n");
482	}
483
484	platform_set_drvdata(pdev, wdt_data);
485	watchdog_stop_on_reboot(wdd);
486	watchdog_stop_on_unregister(wdd);
487	ret = devm_watchdog_register_device(dev, wdd);
488	if (ret)
489		return ret;
490
491	dev_info(dev, "Watchdog registered with %ds timeout\n", wdd->timeout);
492
493	return 0;
494}
495
 
496/* Disable watchdog if it is active during suspend */
497static int kempld_wdt_suspend(struct platform_device *pdev,
498				pm_message_t message)
499{
500	struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
501	struct kempld_device_data *pld = wdt_data->pld;
502	struct watchdog_device *wdd = &wdt_data->wdd;
503
504	kempld_get_mutex(pld);
505	wdt_data->pm_status_store = kempld_read8(pld, KEMPLD_WDT_CFG);
506	kempld_release_mutex(pld);
507
508	kempld_wdt_update_timeouts(wdt_data);
509
510	if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
511		return kempld_wdt_stop(wdd);
512
513	return 0;
514}
515
516/* Enable watchdog and configure it if necessary */
517static int kempld_wdt_resume(struct platform_device *pdev)
518{
519	struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
520	struct watchdog_device *wdd = &wdt_data->wdd;
521
522	/*
523	 * If watchdog was stopped before suspend be sure it gets disabled
524	 * again, for the case BIOS has enabled it during resume
525	 */
526	if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
527		return kempld_wdt_start(wdd);
528	else
529		return kempld_wdt_stop(wdd);
530}
 
 
 
 
531
532static struct platform_driver kempld_wdt_driver = {
533	.driver		= {
534		.name	= "kempld-wdt",
535	},
536	.probe		= kempld_wdt_probe,
537	.suspend	= pm_ptr(kempld_wdt_suspend),
538	.resume		= pm_ptr(kempld_wdt_resume),
539};
540
541module_platform_driver(kempld_wdt_driver);
542
543MODULE_DESCRIPTION("KEM PLD Watchdog Driver");
544MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
545MODULE_LICENSE("GPL");