2 * Watchdog driver for Cirrus Logic EP93xx family of devices.
4 * Copyright (c) 2004 Ray Lehtiniemi
5 * Copyright (c) 2006 Tower Technologies
6 * Based on ep93xx driver, bits from alim7101_wdt.c
8 * Authors: Ray Lehtiniemi <rayl@mail.com>,
9 * Alessandro Zummo <a.zummo@towertech.it>
11 * Copyright (c) 2012 H Hartley Sweeten <hsweeten@visionengravers.com>
12 * Convert to a platform device and use the watchdog framework API
14 * This file is licensed under the terms of the GNU General Public
15 * License version 2. This program is licensed "as is" without any
16 * warranty of any kind, whether express or implied.
18 * This watchdog fires after 250msec, which is a too short interval
19 * for us to rely on the user space daemon alone. So we ping the
20 * wdt each ~200msec and eventually stop doing it if the user space
24 #include <linux/platform_device.h>
25 #include <linux/module.h>
26 #include <linux/watchdog.h>
29 /* default timeout (secs) */
30 #define WDT_TIMEOUT 30
32 static bool nowayout
= WATCHDOG_NOWAYOUT
;
33 module_param(nowayout
, bool, 0);
34 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started");
36 static unsigned int timeout
;
37 module_param(timeout
, uint
, 0);
38 MODULE_PARM_DESC(timeout
, "Watchdog timeout in seconds.");
40 #define EP93XX_WATCHDOG 0x00
41 #define EP93XX_WDSTATUS 0x04
43 struct ep93xx_wdt_priv
{
45 struct watchdog_device wdd
;
48 static int ep93xx_wdt_start(struct watchdog_device
*wdd
)
50 struct ep93xx_wdt_priv
*priv
= watchdog_get_drvdata(wdd
);
52 writel(0xaaaa, priv
->mmio
+ EP93XX_WATCHDOG
);
57 static int ep93xx_wdt_stop(struct watchdog_device
*wdd
)
59 struct ep93xx_wdt_priv
*priv
= watchdog_get_drvdata(wdd
);
61 writel(0xaa55, priv
->mmio
+ EP93XX_WATCHDOG
);
66 static int ep93xx_wdt_ping(struct watchdog_device
*wdd
)
68 struct ep93xx_wdt_priv
*priv
= watchdog_get_drvdata(wdd
);
70 writel(0x5555, priv
->mmio
+ EP93XX_WATCHDOG
);
75 static const struct watchdog_info ep93xx_wdt_ident
= {
76 .options
= WDIOF_CARDRESET
|
80 .identity
= "EP93xx Watchdog",
83 static const struct watchdog_ops ep93xx_wdt_ops
= {
85 .start
= ep93xx_wdt_start
,
86 .stop
= ep93xx_wdt_stop
,
87 .ping
= ep93xx_wdt_ping
,
90 static int ep93xx_wdt_probe(struct platform_device
*pdev
)
92 struct ep93xx_wdt_priv
*priv
;
93 struct watchdog_device
*wdd
;
98 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
102 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
103 priv
->mmio
= devm_ioremap_resource(&pdev
->dev
, res
);
104 if (IS_ERR(priv
->mmio
))
105 return PTR_ERR(priv
->mmio
);
107 val
= readl(priv
->mmio
+ EP93XX_WATCHDOG
);
110 wdd
->bootstatus
= (val
& 0x01) ? WDIOF_CARDRESET
: 0;
111 wdd
->info
= &ep93xx_wdt_ident
;
112 wdd
->ops
= &ep93xx_wdt_ops
;
113 wdd
->min_timeout
= 1;
114 wdd
->max_hw_heartbeat_ms
= 200;
115 wdd
->parent
= &pdev
->dev
;
117 watchdog_set_nowayout(wdd
, nowayout
);
119 wdd
->timeout
= WDT_TIMEOUT
;
120 watchdog_init_timeout(wdd
, timeout
, &pdev
->dev
);
122 watchdog_set_drvdata(wdd
, priv
);
124 ret
= devm_watchdog_register_device(&pdev
->dev
, wdd
);
128 dev_info(&pdev
->dev
, "EP93XX watchdog driver %s\n",
129 (val
& 0x08) ? " (nCS1 disable detected)" : "");
134 static struct platform_driver ep93xx_wdt_driver
= {
136 .name
= "ep93xx-wdt",
138 .probe
= ep93xx_wdt_probe
,
141 module_platform_driver(ep93xx_wdt_driver
);
143 MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>");
144 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
145 MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
146 MODULE_DESCRIPTION("EP93xx Watchdog");
147 MODULE_LICENSE("GPL");