2 * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
4 * (C) Copyright 2013 - 2014 Xilinx, Inc.
5 * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 #include <linux/err.h>
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/ioport.h>
20 #include <linux/watchdog.h>
23 #include <linux/of_device.h>
24 #include <linux/of_address.h>
26 /* Register offsets for the Wdt device */
27 #define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */
28 #define XWT_TWCSR1_OFFSET 0x4 /* Control/Status Register1 */
29 #define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */
31 /* Control/Status Register Masks */
32 #define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */
33 #define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */
34 #define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */
36 /* Control/Status Register 0/1 bits */
37 #define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */
39 /* SelfTest constants */
40 #define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000
41 #define XWT_TIMER_FAILED 0xFFFFFFFF
43 #define WATCHDOG_NAME "Xilinx Watchdog"
44 #define PFX WATCHDOG_NAME ": "
51 static struct xwdt_device xdev
;
55 static DEFINE_SPINLOCK(spinlock
);
57 static int xilinx_wdt_start(struct watchdog_device
*wdd
)
59 u32 control_status_reg
;
63 /* Clean previous status and enable the watchdog timer */
64 control_status_reg
= ioread32(xdev
.base
+ XWT_TWCSR0_OFFSET
);
65 control_status_reg
|= (XWT_CSR0_WRS_MASK
| XWT_CSR0_WDS_MASK
);
67 iowrite32((control_status_reg
| XWT_CSR0_EWDT1_MASK
),
68 xdev
.base
+ XWT_TWCSR0_OFFSET
);
70 iowrite32(XWT_CSRX_EWDT2_MASK
, xdev
.base
+ XWT_TWCSR1_OFFSET
);
72 spin_unlock(&spinlock
);
77 static int xilinx_wdt_stop(struct watchdog_device
*wdd
)
79 u32 control_status_reg
;
83 control_status_reg
= ioread32(xdev
.base
+ XWT_TWCSR0_OFFSET
);
85 iowrite32((control_status_reg
& ~XWT_CSR0_EWDT1_MASK
),
86 xdev
.base
+ XWT_TWCSR0_OFFSET
);
88 iowrite32(0, xdev
.base
+ XWT_TWCSR1_OFFSET
);
90 spin_unlock(&spinlock
);
91 pr_info("Stopped!\n");
96 static int xilinx_wdt_keepalive(struct watchdog_device
*wdd
)
98 u32 control_status_reg
;
100 spin_lock(&spinlock
);
102 control_status_reg
= ioread32(xdev
.base
+ XWT_TWCSR0_OFFSET
);
103 control_status_reg
|= (XWT_CSR0_WRS_MASK
| XWT_CSR0_WDS_MASK
);
104 iowrite32(control_status_reg
, xdev
.base
+ XWT_TWCSR0_OFFSET
);
106 spin_unlock(&spinlock
);
111 static const struct watchdog_info xilinx_wdt_ident
= {
112 .options
= WDIOF_MAGICCLOSE
|
114 .firmware_version
= 1,
115 .identity
= WATCHDOG_NAME
,
118 static const struct watchdog_ops xilinx_wdt_ops
= {
119 .owner
= THIS_MODULE
,
120 .start
= xilinx_wdt_start
,
121 .stop
= xilinx_wdt_stop
,
122 .ping
= xilinx_wdt_keepalive
,
125 static struct watchdog_device xilinx_wdt_wdd
= {
126 .info
= &xilinx_wdt_ident
,
127 .ops
= &xilinx_wdt_ops
,
130 static u32
xwdt_selftest(void)
136 spin_lock(&spinlock
);
138 timer_value1
= ioread32(xdev
.base
+ XWT_TBR_OFFSET
);
139 timer_value2
= ioread32(xdev
.base
+ XWT_TBR_OFFSET
);
142 ((i
<= XWT_MAX_SELFTEST_LOOP_COUNT
) &&
143 (timer_value2
== timer_value1
)); i
++) {
144 timer_value2
= ioread32(xdev
.base
+ XWT_TBR_OFFSET
);
147 spin_unlock(&spinlock
);
149 if (timer_value2
!= timer_value1
)
150 return ~XWT_TIMER_FAILED
;
152 return XWT_TIMER_FAILED
;
155 static int xwdt_probe(struct platform_device
*pdev
)
160 struct resource
*res
;
161 bool no_timeout
= false;
163 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
164 xdev
.base
= devm_ioremap_resource(&pdev
->dev
, res
);
165 if (IS_ERR(xdev
.base
))
166 return PTR_ERR(xdev
.base
);
168 pfreq
= (u32
*)of_get_property(pdev
->dev
.of_node
,
169 "clock-frequency", NULL
);
172 pr_warn("The watchdog clock frequency cannot be obtained!\n");
176 tmptr
= (u32
*)of_get_property(pdev
->dev
.of_node
,
177 "xlnx,wdt-interval", NULL
);
179 pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
182 xdev
.wdt_interval
= *tmptr
;
185 tmptr
= (u32
*)of_get_property(pdev
->dev
.of_node
,
186 "xlnx,wdt-enable-once", NULL
);
188 pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
189 watchdog_set_nowayout(&xilinx_wdt_wdd
, true);
193 * Twice of the 2^wdt_interval / freq because the first wdt overflow is
194 * ignored (interrupt), reset is only generated at second wdt overflow
197 timeout
= 2 * ((1<<xdev
.wdt_interval
) / *pfreq
);
199 rc
= xwdt_selftest();
200 if (rc
== XWT_TIMER_FAILED
) {
201 pr_err("SelfTest routine error!\n");
205 rc
= watchdog_register_device(&xilinx_wdt_wdd
);
207 pr_err("cannot register watchdog (err=%d)\n", rc
);
211 dev_info(&pdev
->dev
, "Xilinx Watchdog Timer at %p with timeout %ds\n",
217 static int xwdt_remove(struct platform_device
*dev
)
219 watchdog_unregister_device(&xilinx_wdt_wdd
);
224 /* Match table for of_platform binding */
225 static struct of_device_id xwdt_of_match
[] = {
226 { .compatible
= "xlnx,xps-timebase-wdt-1.00.a", },
227 { .compatible
= "xlnx,xps-timebase-wdt-1.01.a", },
230 MODULE_DEVICE_TABLE(of
, xwdt_of_match
);
232 static struct platform_driver xwdt_driver
= {
234 .remove
= xwdt_remove
,
236 .owner
= THIS_MODULE
,
237 .name
= WATCHDOG_NAME
,
238 .of_match_table
= xwdt_of_match
,
242 module_platform_driver(xwdt_driver
);
244 MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
245 MODULE_DESCRIPTION("Xilinx Watchdog driver");
246 MODULE_LICENSE("GPL v2");