of_xilinx_wdt.c revision f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18
1e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/*
29419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
39419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek *
4d14fd9645501444f06034339118de56686e25dfbMichal Simek * (C) Copyright 2013 - 2014 Xilinx, Inc.
59419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
69419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek *
79419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * This program is free software; you can redistribute it and/or
89419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * modify it under the terms of the GNU General Public License
99419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * as published by the Free Software Foundation; either version
109419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * 2 of the License, or (at your option) any later version.
119419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek */
12e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
1327c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches
15f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek#include <linux/err.h>
16e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/module.h>
17e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/types.h>
18e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/kernel.h>
19e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/ioport.h>
20e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/watchdog.h>
21e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/io.h>
22e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of.h>
23e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of_device.h>
24e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of_address.h>
25e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
26e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Register offsets for the Wdt device */
27e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TWCSR0_OFFSET   0x0 /* Control/Status Register0 */
28e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TWCSR1_OFFSET   0x4 /* Control/Status Register1 */
29e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TBR_OFFSET      0x8 /* Timebase Register Offset */
30e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
31e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Control/Status Register Masks  */
32e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_WRS_MASK   0x00000008 /* Reset status */
33e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_WDS_MASK   0x00000004 /* Timer state  */
34e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */
35e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
36e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Control/Status Register 0/1 bits  */
37e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */
38e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
39e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* SelfTest constants */
40e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000
41e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TIMER_FAILED            0xFFFFFFFF
42e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
43e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define WATCHDOG_NAME     "Xilinx Watchdog"
44e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define PFX WATCHDOG_NAME ": "
45e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
46e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastruct xwdt_device {
47e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	void __iomem *base;
48e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	u32 wdt_interval;
49e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera};
50e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
51e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct xwdt_device xdev;
52e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
53e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic  u32 timeout;
54e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic  u8  no_timeout;
55e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
56e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic  DEFINE_SPINLOCK(spinlock);
57e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
58d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic int xilinx_wdt_start(struct watchdog_device *wdd)
59e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{
605cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek	u32 control_status_reg;
615cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek
62e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_lock(&spinlock);
63e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
64e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	/* Clean previous status and enable the watchdog timer */
65e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
66e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
67e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
68e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
69e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera				xdev.base + XWT_TWCSR0_OFFSET);
70e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
71e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
72e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
73e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_unlock(&spinlock);
74d14fd9645501444f06034339118de56686e25dfbMichal Simek
75d14fd9645501444f06034339118de56686e25dfbMichal Simek	return 0;
76e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}
77e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
78d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic int xilinx_wdt_stop(struct watchdog_device *wdd)
79e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{
805cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek	u32 control_status_reg;
815cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek
82e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_lock(&spinlock);
83e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
84e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
85e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
86e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
87e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera				xdev.base + XWT_TWCSR0_OFFSET);
88e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
89e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
90e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
91e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_unlock(&spinlock);
9227c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches	pr_info("Stopped!\n");
93d14fd9645501444f06034339118de56686e25dfbMichal Simek
94d14fd9645501444f06034339118de56686e25dfbMichal Simek	return 0;
95e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}
96e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
97d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic int xilinx_wdt_keepalive(struct watchdog_device *wdd)
98e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{
995cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek	u32 control_status_reg;
1005cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek
101e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_lock(&spinlock);
102e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
103e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
104e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
105e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
106e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
107e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_unlock(&spinlock);
108e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
109d14fd9645501444f06034339118de56686e25dfbMichal Simek	return 0;
110d14fd9645501444f06034339118de56686e25dfbMichal Simek}
111e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
112d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic const struct watchdog_info xilinx_wdt_ident = {
113d14fd9645501444f06034339118de56686e25dfbMichal Simek	.options =  WDIOF_MAGICCLOSE |
114d14fd9645501444f06034339118de56686e25dfbMichal Simek		    WDIOF_KEEPALIVEPING,
115d14fd9645501444f06034339118de56686e25dfbMichal Simek	.firmware_version =	1,
116d14fd9645501444f06034339118de56686e25dfbMichal Simek	.identity =	WATCHDOG_NAME,
117d14fd9645501444f06034339118de56686e25dfbMichal Simek};
118e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
119d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic const struct watchdog_ops xilinx_wdt_ops = {
120d14fd9645501444f06034339118de56686e25dfbMichal Simek	.owner = THIS_MODULE,
121d14fd9645501444f06034339118de56686e25dfbMichal Simek	.start = xilinx_wdt_start,
122d14fd9645501444f06034339118de56686e25dfbMichal Simek	.stop = xilinx_wdt_stop,
123d14fd9645501444f06034339118de56686e25dfbMichal Simek	.ping = xilinx_wdt_keepalive,
124d14fd9645501444f06034339118de56686e25dfbMichal Simek};
125e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
126d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic struct watchdog_device xilinx_wdt_wdd = {
127d14fd9645501444f06034339118de56686e25dfbMichal Simek	.info = &xilinx_wdt_ident,
128d14fd9645501444f06034339118de56686e25dfbMichal Simek	.ops = &xilinx_wdt_ops,
129d14fd9645501444f06034339118de56686e25dfbMichal Simek};
130e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
131e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic u32 xwdt_selftest(void)
132e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{
133e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	int i;
134e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	u32 timer_value1;
135e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	u32 timer_value2;
136e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
137e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_lock(&spinlock);
138e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
139e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
140e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
141e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
142e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	for (i = 0;
143e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
144e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera			(timer_value2 == timer_value1)); i++) {
145e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
146e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	}
147e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
148e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	spin_unlock(&spinlock);
149e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
150e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	if (timer_value2 != timer_value1)
151e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		return ~XWT_TIMER_FAILED;
152e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	else
153e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		return XWT_TIMER_FAILED;
154e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}
155e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
1562d991a164a61858012651e13c59521975504e260Bill Pembertonstatic int xwdt_probe(struct platform_device *pdev)
157e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{
158e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	int rc;
159e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	u32 *tmptr;
160e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	u32 *pfreq;
161f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek	struct resource *res;
162e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
163e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	no_timeout = 0;
164e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
165f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
166f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek	xdev.base = devm_ioremap_resource(&pdev->dev, res);
167f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek	if (IS_ERR(xdev.base))
168f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek		return PTR_ERR(xdev.base);
169f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek
17090fe6c608f8d46e5bb3f31c2d5e1c90475253f79Michal Simek	pfreq = (u32 *)of_get_property(pdev->dev.of_node,
171e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera					"clock-frequency", NULL);
172e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
173e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	if (pfreq == NULL) {
17427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches		pr_warn("The watchdog clock frequency cannot be obtained!\n");
175e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		no_timeout = 1;
176e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	}
177e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
178e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	tmptr = (u32 *)of_get_property(pdev->dev.of_node,
179e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera					"xlnx,wdt-interval", NULL);
180e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	if (tmptr == NULL) {
18127c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches		pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
182e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		no_timeout = 1;
183e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	} else {
184e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		xdev.wdt_interval = *tmptr;
185e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	}
186e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
187e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	tmptr = (u32 *)of_get_property(pdev->dev.of_node,
188e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera					"xlnx,wdt-enable-once", NULL);
189e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	if (tmptr == NULL) {
19027c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches		pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
191d14fd9645501444f06034339118de56686e25dfbMichal Simek		watchdog_set_nowayout(&xilinx_wdt_wdd, true);
192e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	}
193e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
194e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/*
195e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera *  Twice of the 2^wdt_interval / freq  because the first wdt overflow is
196e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera *  ignored (interrupt), reset is only generated at second wdt overflow
197e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera */
198e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	if (!no_timeout)
199e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
200e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
201e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	rc = xwdt_selftest();
202e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	if (rc == XWT_TIMER_FAILED) {
20327c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches		pr_err("SelfTest routine error!\n");
204f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek		return rc;
205e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	}
206e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
207d14fd9645501444f06034339118de56686e25dfbMichal Simek	rc = watchdog_register_device(&xilinx_wdt_wdd);
208e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	if (rc) {
209d14fd9645501444f06034339118de56686e25dfbMichal Simek		pr_err("cannot register watchdog (err=%d)\n", rc);
210f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek		return rc;
211e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	}
212e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
213d14fd9645501444f06034339118de56686e25dfbMichal Simek	dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
214d14fd9645501444f06034339118de56686e25dfbMichal Simek		 xdev.base, timeout);
215e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
216e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	return 0;
217e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}
218e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
2194b12b896c27c3b54592816606679f5b02f638930Bill Pembertonstatic int xwdt_remove(struct platform_device *dev)
220e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{
221d14fd9645501444f06034339118de56686e25dfbMichal Simek	watchdog_unregister_device(&xilinx_wdt_wdd);
222e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
223e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	return 0;
224e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}
225e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
226e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Match table for of_platform binding */
2271d1313686422db3bffb2e7bd8eb2ccd9027d3783Bill Pembertonstatic struct of_device_id xwdt_of_match[] = {
2288fce9b367d672332d2d101175b10737ee5c18b59Michal Simek	{ .compatible = "xlnx,xps-timebase-wdt-1.00.a", },
229e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	{ .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
230e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	{},
231e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera};
232e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DEVICE_TABLE(of, xwdt_of_match);
233e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
234e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct platform_driver xwdt_driver = {
235e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	.probe       = xwdt_probe,
23682268714bdf06bc06135efb707a9de590ab2d294Bill Pemberton	.remove      = xwdt_remove,
237e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	.driver = {
238e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		.owner = THIS_MODULE,
239e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		.name  = WATCHDOG_NAME,
240e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera		.of_match_table = xwdt_of_match,
241e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera	},
242e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera};
243e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
244b8ec61189f3b4cd9d1b2856342f5d7676151d01cAxel Linmodule_platform_driver(xwdt_driver);
245e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera
246e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
247e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DESCRIPTION("Xilinx Watchdog driver");
2489419c07ccebf6080159b4440dab9b3e484c96d7aMichal SimekMODULE_LICENSE("GPL v2");
249