Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * Watchdog driver for Technologic Systems TS-72xx based SBCs
  3 * (TS-7200, TS-7250 and TS-7260). These boards have external
  4 * glue logic CPLD chip, which includes programmable watchdog
  5 * timer.
  6 *
  7 * Copyright (c) 2009 Mika Westerberg <mika.westerberg@iki.fi>
  8 *
  9 * This driver is based on ep93xx_wdt and wm831x_wdt drivers.
 10 *
 11 * This file is licensed under the terms of the GNU General Public
 12 * License version 2. This program is licensed "as is" without any
 13 * warranty of any kind, whether express or implied.
 14 */
 15
 16#include <linux/fs.h>
 17#include <linux/io.h>
 18#include <linux/module.h>
 19#include <linux/moduleparam.h>
 20#include <linux/miscdevice.h>
 21#include <linux/mutex.h>
 22#include <linux/platform_device.h>
 23#include <linux/slab.h>
 24#include <linux/watchdog.h>
 25#include <linux/uaccess.h>
 26
 27#define TS72XX_WDT_FEED_VAL		0x05
 28#define TS72XX_WDT_DEFAULT_TIMEOUT	8
 29
 30static int timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
 31module_param(timeout, int, 0);
 32MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. "
 33			  "(1 <= timeout <= 8, default="
 34			  __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT)
 35			  ")");
 36
 37static int nowayout = WATCHDOG_NOWAYOUT;
 38module_param(nowayout, int, 0);
 39MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 40
 41/**
 42 * struct ts72xx_wdt - watchdog control structure
 43 * @lock: lock that protects this structure
 44 * @regval: watchdog timeout value suitable for control register
 45 * @flags: flags controlling watchdog device state
 46 * @control_reg: watchdog control register
 47 * @feed_reg: watchdog feed register
 48 * @pdev: back pointer to platform dev
 49 */
 50struct ts72xx_wdt {
 51	struct mutex	lock;
 52	int		regval;
 53
 54#define TS72XX_WDT_BUSY_FLAG		1
 55#define TS72XX_WDT_EXPECT_CLOSE_FLAG	2
 56	int		flags;
 57
 
 
 
 
 58	void __iomem	*control_reg;
 59	void __iomem	*feed_reg;
 60
 61	struct platform_device *pdev;
 62};
 63
 64struct platform_device *ts72xx_wdt_pdev;
 65
 66/*
 67 * TS-72xx Watchdog supports following timeouts (value written
 68 * to control register):
 69 *	value	description
 70 *	-------------------------
 71 *	0x00	watchdog disabled
 72 *	0x01	250ms
 73 *	0x02	500ms
 74 *	0x03	1s
 75 *	0x04	reserved
 76 *	0x05	2s
 77 *	0x06	4s
 78 *	0x07	8s
 79 *
 80 * Timeouts below 1s are not very usable so we don't
 81 * allow them at all.
 82 *
 83 * We provide two functions that convert between these:
 84 * timeout_to_regval() and regval_to_timeout().
 85 */
 86static const struct {
 87	int	timeout;
 88	int	regval;
 89} ts72xx_wdt_map[] = {
 90	{ 1, 3 },
 91	{ 2, 5 },
 92	{ 4, 6 },
 93	{ 8, 7 },
 94};
 95
 96/**
 97 * timeout_to_regval() - converts given timeout to control register value
 98 * @new_timeout: timeout in seconds to be converted
 99 *
100 * Function converts given @new_timeout into valid value that can
101 * be programmed into watchdog control register. When conversion is
102 * not possible, function returns %-EINVAL.
103 */
104static int timeout_to_regval(int new_timeout)
105{
106	int i;
107
108	/* first limit it to 1 - 8 seconds */
109	new_timeout = clamp_val(new_timeout, 1, 8);
110
111	for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
112		if (ts72xx_wdt_map[i].timeout >= new_timeout)
113			return ts72xx_wdt_map[i].regval;
114	}
115
116	return -EINVAL;
117}
118
119/**
120 * regval_to_timeout() - converts control register value to timeout
121 * @regval: control register value to be converted
122 *
123 * Function converts given @regval to timeout in seconds (1, 2, 4 or 8).
124 * If @regval cannot be converted, function returns %-EINVAL.
125 */
126static int regval_to_timeout(int regval)
127{
128	int i;
129
130	for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
131		if (ts72xx_wdt_map[i].regval == regval)
132			return ts72xx_wdt_map[i].timeout;
133	}
134
135	return -EINVAL;
136}
137
138/**
139 * ts72xx_wdt_kick() - kick the watchdog
140 * @wdt: watchdog to be kicked
141 *
142 * Called with @wdt->lock held.
143 */
144static inline void ts72xx_wdt_kick(struct ts72xx_wdt *wdt)
145{
146	__raw_writeb(TS72XX_WDT_FEED_VAL, wdt->feed_reg);
147}
148
149/**
150 * ts72xx_wdt_start() - starts the watchdog timer
151 * @wdt: watchdog to be started
152 *
153 * This function programs timeout to watchdog timer
154 * and starts it.
155 *
156 * Called with @wdt->lock held.
157 */
158static void ts72xx_wdt_start(struct ts72xx_wdt *wdt)
159{
160	/*
161	 * To program the wdt, it first must be "fed" and
162	 * only after that (within 30 usecs) the configuration
163	 * can be changed.
164	 */
165	ts72xx_wdt_kick(wdt);
166	__raw_writeb((u8)wdt->regval, wdt->control_reg);
167}
168
169/**
170 * ts72xx_wdt_stop() - stops the watchdog timer
171 * @wdt: watchdog to be stopped
172 *
173 * Called with @wdt->lock held.
174 */
175static void ts72xx_wdt_stop(struct ts72xx_wdt *wdt)
176{
177	ts72xx_wdt_kick(wdt);
178	__raw_writeb(0, wdt->control_reg);
179}
180
181static int ts72xx_wdt_open(struct inode *inode, struct file *file)
182{
183	struct ts72xx_wdt *wdt = platform_get_drvdata(ts72xx_wdt_pdev);
184	int regval;
185
186	/*
187	 * Try to convert default timeout to valid register
188	 * value first.
189	 */
190	regval = timeout_to_regval(timeout);
191	if (regval < 0) {
192		dev_err(&wdt->pdev->dev,
193			"failed to convert timeout (%d) to register value\n",
194			timeout);
195		return -EINVAL;
196	}
197
198	if (mutex_lock_interruptible(&wdt->lock))
199		return -ERESTARTSYS;
200
201	if ((wdt->flags & TS72XX_WDT_BUSY_FLAG) != 0) {
202		mutex_unlock(&wdt->lock);
203		return -EBUSY;
204	}
205
206	wdt->flags = TS72XX_WDT_BUSY_FLAG;
207	wdt->regval = regval;
208	file->private_data = wdt;
209
210	ts72xx_wdt_start(wdt);
211
212	mutex_unlock(&wdt->lock);
213	return nonseekable_open(inode, file);
214}
215
216static int ts72xx_wdt_release(struct inode *inode, struct file *file)
217{
218	struct ts72xx_wdt *wdt = file->private_data;
219
220	if (mutex_lock_interruptible(&wdt->lock))
221		return -ERESTARTSYS;
222
223	if ((wdt->flags & TS72XX_WDT_EXPECT_CLOSE_FLAG) != 0) {
224		ts72xx_wdt_stop(wdt);
 
 
 
 
 
225	} else {
226		dev_warn(&wdt->pdev->dev,
227			 "TS-72XX WDT device closed unexpectly. "
228			 "Watchdog timer will not stop!\n");
229		/*
230		 * Kick it one more time, to give userland some time
231		 * to recover (for example, respawning the kicker
232		 * daemon).
233		 */
234		ts72xx_wdt_kick(wdt);
235	}
236
237	wdt->flags = 0;
238
239	mutex_unlock(&wdt->lock);
240	return 0;
241}
242
243static ssize_t ts72xx_wdt_write(struct file *file,
244				const char __user *data,
245				size_t len,
246				loff_t *ppos)
247{
248	struct ts72xx_wdt *wdt = file->private_data;
249
250	if (!len)
251		return 0;
252
253	if (mutex_lock_interruptible(&wdt->lock))
254		return -ERESTARTSYS;
255
256	ts72xx_wdt_kick(wdt);
257
258	/*
259	 * Support for magic character closing. User process
260	 * writes 'V' into the device, just before it is closed.
261	 * This means that we know that the wdt timer can be
262	 * stopped after user closes the device.
263	 */
264	if (!nowayout) {
265		int i;
266
267		for (i = 0; i < len; i++) {
268			char c;
269
270			/* In case it was set long ago */
271			wdt->flags &= ~TS72XX_WDT_EXPECT_CLOSE_FLAG;
272
273			if (get_user(c, data + i)) {
274				mutex_unlock(&wdt->lock);
275				return -EFAULT;
276			}
277			if (c == 'V') {
278				wdt->flags |= TS72XX_WDT_EXPECT_CLOSE_FLAG;
279				break;
280			}
281		}
282	}
283
284	mutex_unlock(&wdt->lock);
285	return len;
286}
287
288static const struct watchdog_info winfo = {
289	.options		= WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
 
290				  WDIOF_MAGICCLOSE,
291	.firmware_version	= 1,
292	.identity		= "TS-72XX WDT",
293};
294
295static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd,
296			     unsigned long arg)
297{
298	struct ts72xx_wdt *wdt = file->private_data;
299	void __user *argp = (void __user *)arg;
300	int __user *p = (int __user *)argp;
301	int error = 0;
302
303	if (mutex_lock_interruptible(&wdt->lock))
304		return -ERESTARTSYS;
305
306	switch (cmd) {
307	case WDIOC_GETSUPPORT:
308		error = copy_to_user(argp, &winfo, sizeof(winfo));
309		break;
310
311	case WDIOC_GETSTATUS:
312	case WDIOC_GETBOOTSTATUS:
313		return put_user(0, p);
314
315	case WDIOC_KEEPALIVE:
316		ts72xx_wdt_kick(wdt);
317		break;
318
319	case WDIOC_SETOPTIONS: {
320		int options;
321
322		if (get_user(options, p)) {
323			error = -EFAULT;
324			break;
325		}
326
327		error = -EINVAL;
328
329		if ((options & WDIOS_DISABLECARD) != 0) {
330			ts72xx_wdt_stop(wdt);
331			error = 0;
332		}
333		if ((options & WDIOS_ENABLECARD) != 0) {
334			ts72xx_wdt_start(wdt);
335			error = 0;
336		}
337
338		break;
339	}
340
341	case WDIOC_SETTIMEOUT: {
342		int new_timeout;
343
344		if (get_user(new_timeout, p)) {
345			error = -EFAULT;
346		} else {
347			int regval;
348
349			regval = timeout_to_regval(new_timeout);
350			if (regval < 0) {
351				error = -EINVAL;
352			} else {
353				ts72xx_wdt_stop(wdt);
354				wdt->regval = regval;
355				ts72xx_wdt_start(wdt);
356			}
357		}
358		if (error)
359			break;
360
361		/*FALLTHROUGH*/
362	}
363
364	case WDIOC_GETTIMEOUT:
365		if (put_user(regval_to_timeout(wdt->regval), p))
366			error = -EFAULT;
367		break;
368
369	default:
370		error = -ENOTTY;
371		break;
372	}
373
374	mutex_unlock(&wdt->lock);
375	return error;
376}
377
378static const struct file_operations ts72xx_wdt_fops = {
379	.owner		= THIS_MODULE,
380	.llseek		= no_llseek,
381	.open		= ts72xx_wdt_open,
382	.release	= ts72xx_wdt_release,
383	.write		= ts72xx_wdt_write,
384	.unlocked_ioctl	= ts72xx_wdt_ioctl,
385};
386
387static struct miscdevice ts72xx_wdt_miscdev = {
388	.minor		= WATCHDOG_MINOR,
389	.name		= "watchdog",
390	.fops		= &ts72xx_wdt_fops,
391};
392
393static __devinit int ts72xx_wdt_probe(struct platform_device *pdev)
394{
395	struct ts72xx_wdt *wdt;
396	struct resource *r1, *r2;
397	int error = 0;
398
399	wdt = kzalloc(sizeof(struct ts72xx_wdt), GFP_KERNEL);
400	if (!wdt) {
401		dev_err(&pdev->dev, "failed to allocate memory\n");
402		return -ENOMEM;
403	}
404
405	r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
406	if (!r1) {
407		dev_err(&pdev->dev, "failed to get memory resource\n");
408		error = -ENODEV;
409		goto fail;
410	}
411
412	r1 = request_mem_region(r1->start, resource_size(r1), pdev->name);
413	if (!r1) {
414		dev_err(&pdev->dev, "cannot request memory region\n");
415		error = -EBUSY;
416		goto fail;
417	}
418
419	wdt->control_reg = ioremap(r1->start, resource_size(r1));
420	if (!wdt->control_reg) {
421		dev_err(&pdev->dev, "failed to map memory\n");
422		error = -ENODEV;
423		goto fail_free_control;
424	}
425
426	r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
427	if (!r2) {
428		dev_err(&pdev->dev, "failed to get memory resource\n");
429		error = -ENODEV;
430		goto fail_unmap_control;
431	}
432
433	r2 = request_mem_region(r2->start, resource_size(r2), pdev->name);
434	if (!r2) {
435		dev_err(&pdev->dev, "cannot request memory region\n");
436		error = -EBUSY;
437		goto fail_unmap_control;
438	}
439
440	wdt->feed_reg = ioremap(r2->start, resource_size(r2));
441	if (!wdt->feed_reg) {
442		dev_err(&pdev->dev, "failed to map memory\n");
443		error = -ENODEV;
444		goto fail_free_feed;
445	}
446
447	platform_set_drvdata(pdev, wdt);
448	ts72xx_wdt_pdev = pdev;
449	wdt->pdev = pdev;
450	mutex_init(&wdt->lock);
451
452	/* make sure that the watchdog is disabled */
453	ts72xx_wdt_stop(wdt);
454
455	error = misc_register(&ts72xx_wdt_miscdev);
456	if (error) {
457		dev_err(&pdev->dev, "failed to register miscdev\n");
458		goto fail_unmap_feed;
459	}
 
 
 
 
 
 
 
 
 
460
461	dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
462
463	return 0;
464
465fail_unmap_feed:
466	platform_set_drvdata(pdev, NULL);
467	iounmap(wdt->feed_reg);
468fail_free_feed:
469	release_mem_region(r2->start, resource_size(r2));
470fail_unmap_control:
471	iounmap(wdt->control_reg);
472fail_free_control:
473	release_mem_region(r1->start, resource_size(r1));
474fail:
475	kfree(wdt);
476	return error;
477}
478
479static __devexit int ts72xx_wdt_remove(struct platform_device *pdev)
480{
481	struct ts72xx_wdt *wdt = platform_get_drvdata(pdev);
482	struct resource *res;
483	int error;
484
485	error = misc_deregister(&ts72xx_wdt_miscdev);
486	platform_set_drvdata(pdev, NULL);
487
488	iounmap(wdt->feed_reg);
489	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
490	release_mem_region(res->start, resource_size(res));
491
492	iounmap(wdt->control_reg);
493	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
494	release_mem_region(res->start, resource_size(res));
495
496	kfree(wdt);
497	return error;
498}
499
500static struct platform_driver ts72xx_wdt_driver = {
501	.probe		= ts72xx_wdt_probe,
502	.remove		= __devexit_p(ts72xx_wdt_remove),
503	.driver		= {
504		.name	= "ts72xx-wdt",
505		.owner	= THIS_MODULE,
506	},
507};
508
509static __init int ts72xx_wdt_init(void)
510{
511	return platform_driver_register(&ts72xx_wdt_driver);
512}
513module_init(ts72xx_wdt_init);
514
515static __exit void ts72xx_wdt_exit(void)
516{
517	platform_driver_unregister(&ts72xx_wdt_driver);
518}
519module_exit(ts72xx_wdt_exit);
520
521MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
522MODULE_DESCRIPTION("TS-72xx SBC Watchdog");
523MODULE_LICENSE("GPL");
524MODULE_ALIAS("platform:ts72xx-wdt");
v4.17
  1/*
  2 * Watchdog driver for Technologic Systems TS-72xx based SBCs
  3 * (TS-7200, TS-7250 and TS-7260). These boards have external
  4 * glue logic CPLD chip, which includes programmable watchdog
  5 * timer.
  6 *
  7 * Copyright (c) 2009 Mika Westerberg <mika.westerberg@iki.fi>
  8 *
  9 * This driver is based on ep93xx_wdt and wm831x_wdt drivers.
 10 *
 11 * This file is licensed under the terms of the GNU General Public
 12 * License version 2. This program is licensed "as is" without any
 13 * warranty of any kind, whether express or implied.
 14 */
 15
 
 
 
 
 
 
 16#include <linux/platform_device.h>
 17#include <linux/module.h>
 18#include <linux/watchdog.h>
 19#include <linux/io.h>
 20
 21#define TS72XX_WDT_DEFAULT_TIMEOUT	30
 
 22
 23static int timeout;
 24module_param(timeout, int, 0);
 25MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds.");
 
 
 
 26
 27static bool nowayout = WATCHDOG_NOWAYOUT;
 28module_param(nowayout, bool, 0);
 29MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 30
 31/* priv->control_reg */
 32#define TS72XX_WDT_CTRL_DISABLE		0x00
 33#define TS72XX_WDT_CTRL_250MS		0x01
 34#define TS72XX_WDT_CTRL_500MS		0x02
 35#define TS72XX_WDT_CTRL_1SEC		0x03
 36#define TS72XX_WDT_CTRL_RESERVED	0x04
 37#define TS72XX_WDT_CTRL_2SEC		0x05
 38#define TS72XX_WDT_CTRL_4SEC		0x06
 39#define TS72XX_WDT_CTRL_8SEC		0x07
 
 
 
 
 
 
 
 40
 41/* priv->feed_reg */
 42#define TS72XX_WDT_FEED_VAL		0x05
 43
 44struct ts72xx_wdt_priv {
 45	void __iomem	*control_reg;
 46	void __iomem	*feed_reg;
 47	struct watchdog_device wdd;
 48	unsigned char regval;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 49};
 50
 51static int ts72xx_wdt_start(struct watchdog_device *wdd)
 
 
 
 
 
 
 
 
 52{
 53	struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 54
 55	writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
 56	writeb(priv->regval, priv->control_reg);
 57
 58	return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 59}
 60
 61static int ts72xx_wdt_stop(struct watchdog_device *wdd)
 
 
 
 
 
 
 62{
 63	struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
 64
 65	writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
 66	writeb(TS72XX_WDT_CTRL_DISABLE, priv->control_reg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 67
 68	return 0;
 
 
 
 
 
 
 
 
 
 69}
 70
 71static int ts72xx_wdt_ping(struct watchdog_device *wdd)
 72{
 73	struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
 74
 75	writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 76
 77	return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 78}
 79
 80static int ts72xx_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
 81{
 82	struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
 
 
 83
 84	if (to == 1) {
 85		priv->regval = TS72XX_WDT_CTRL_1SEC;
 86	} else if (to == 2) {
 87		priv->regval = TS72XX_WDT_CTRL_2SEC;
 88	} else if (to <= 4) {
 89		priv->regval = TS72XX_WDT_CTRL_4SEC;
 90		to = 4;
 91	} else {
 92		priv->regval = TS72XX_WDT_CTRL_8SEC;
 93		if (to <= 8)
 94			to = 8;
 
 
 
 
 
 
 95	}
 96
 97	wdd->timeout = to;
 98
 99	if (watchdog_active(wdd)) {
100		ts72xx_wdt_stop(wdd);
101		ts72xx_wdt_start(wdd);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102	}
103
104	return 0;
 
105}
106
107static const struct watchdog_info ts72xx_wdt_ident = {
108	.options		= WDIOF_KEEPALIVEPING |
109				  WDIOF_SETTIMEOUT |
110				  WDIOF_MAGICCLOSE,
111	.firmware_version	= 1,
112	.identity		= "TS-72XX WDT",
113};
114
115static const struct watchdog_ops ts72xx_wdt_ops = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116	.owner		= THIS_MODULE,
117	.start		= ts72xx_wdt_start,
118	.stop		= ts72xx_wdt_stop,
119	.ping		= ts72xx_wdt_ping,
120	.set_timeout	= ts72xx_wdt_settimeout,
 
 
 
 
 
 
 
121};
122
123static int ts72xx_wdt_probe(struct platform_device *pdev)
124{
125	struct ts72xx_wdt_priv *priv;
126	struct watchdog_device *wdd;
127	struct resource *res;
128	int ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
130	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
131	if (!priv)
132		return -ENOMEM;
 
 
 
133
134	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
135	priv->control_reg = devm_ioremap_resource(&pdev->dev, res);
136	if (IS_ERR(priv->control_reg))
137		return PTR_ERR(priv->control_reg);
 
 
138
139	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
140	priv->feed_reg = devm_ioremap_resource(&pdev->dev, res);
141	if (IS_ERR(priv->feed_reg))
142		return PTR_ERR(priv->feed_reg);
143
144	wdd = &priv->wdd;
145	wdd->info = &ts72xx_wdt_ident;
146	wdd->ops = &ts72xx_wdt_ops;
147	wdd->min_timeout = 1;
148	wdd->max_hw_heartbeat_ms = 8000;
149	wdd->parent = &pdev->dev;
150
151	watchdog_set_nowayout(wdd, nowayout);
152
153	wdd->timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
154	watchdog_init_timeout(wdd, timeout, &pdev->dev);
155
156	watchdog_set_drvdata(wdd, priv);
157
158	ret = devm_watchdog_register_device(&pdev->dev, wdd);
159	if (ret)
160		return ret;
161
162	dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
163
164	return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165}
166
167static struct platform_driver ts72xx_wdt_driver = {
168	.probe		= ts72xx_wdt_probe,
 
169	.driver		= {
170		.name	= "ts72xx-wdt",
 
171	},
172};
173
174module_platform_driver(ts72xx_wdt_driver);
 
 
 
 
 
 
 
 
 
 
175
176MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
177MODULE_DESCRIPTION("TS-72xx SBC Watchdog");
178MODULE_LICENSE("GPL");
179MODULE_ALIAS("platform:ts72xx-wdt");