4 * Copyright (C) 2004, 2005 Nokia Corporation
6 * Based on code written by Amit Kucheria and Michael Buesch.
7 * Rewritten by Aaro Koskinen.
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file "COPYING" in the main directory of this
11 * archive for more details.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include <linux/slab.h>
20 #include <linux/errno.h>
21 #include <linux/device.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/mfd/retu.h>
25 #include <linux/watchdog.h>
26 #include <linux/platform_device.h>
28 /* Watchdog timer values in seconds */
29 #define RETU_WDT_MAX_TIMER 63
32 struct retu_dev
*rdev
;
34 struct delayed_work ping_work
;
38 * Since Retu watchdog cannot be disabled in hardware, we must kick it
39 * with a timer until userspace watchdog software takes over. If
40 * CONFIG_WATCHDOG_NOWAYOUT is set, we never start the feeding.
42 static void retu_wdt_ping_enable(struct retu_wdt_dev
*wdev
)
44 retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, RETU_WDT_MAX_TIMER
);
45 schedule_delayed_work(&wdev
->ping_work
,
46 round_jiffies_relative(RETU_WDT_MAX_TIMER
* HZ
/ 2));
49 static void retu_wdt_ping_disable(struct retu_wdt_dev
*wdev
)
51 retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, RETU_WDT_MAX_TIMER
);
52 cancel_delayed_work_sync(&wdev
->ping_work
);
55 static void retu_wdt_ping_work(struct work_struct
*work
)
57 struct retu_wdt_dev
*wdev
= container_of(to_delayed_work(work
),
58 struct retu_wdt_dev
, ping_work
);
59 retu_wdt_ping_enable(wdev
);
62 static int retu_wdt_start(struct watchdog_device
*wdog
)
64 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
66 retu_wdt_ping_disable(wdev
);
68 return retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, wdog
->timeout
);
71 static int retu_wdt_stop(struct watchdog_device
*wdog
)
73 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
75 retu_wdt_ping_enable(wdev
);
80 static int retu_wdt_ping(struct watchdog_device
*wdog
)
82 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
84 return retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, wdog
->timeout
);
87 static int retu_wdt_set_timeout(struct watchdog_device
*wdog
,
90 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
92 wdog
->timeout
= timeout
;
93 return retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, wdog
->timeout
);
96 static const struct watchdog_info retu_wdt_info
= {
97 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
,
98 .identity
= "Retu watchdog",
101 static const struct watchdog_ops retu_wdt_ops
= {
102 .owner
= THIS_MODULE
,
103 .start
= retu_wdt_start
,
104 .stop
= retu_wdt_stop
,
105 .ping
= retu_wdt_ping
,
106 .set_timeout
= retu_wdt_set_timeout
,
109 static int retu_wdt_probe(struct platform_device
*pdev
)
111 struct retu_dev
*rdev
= dev_get_drvdata(pdev
->dev
.parent
);
112 bool nowayout
= WATCHDOG_NOWAYOUT
;
113 struct watchdog_device
*retu_wdt
;
114 struct retu_wdt_dev
*wdev
;
117 retu_wdt
= devm_kzalloc(&pdev
->dev
, sizeof(*retu_wdt
), GFP_KERNEL
);
121 wdev
= devm_kzalloc(&pdev
->dev
, sizeof(*wdev
), GFP_KERNEL
);
125 retu_wdt
->info
= &retu_wdt_info
;
126 retu_wdt
->ops
= &retu_wdt_ops
;
127 retu_wdt
->timeout
= RETU_WDT_MAX_TIMER
;
128 retu_wdt
->min_timeout
= 0;
129 retu_wdt
->max_timeout
= RETU_WDT_MAX_TIMER
;
131 watchdog_set_drvdata(retu_wdt
, wdev
);
132 watchdog_set_nowayout(retu_wdt
, nowayout
);
135 wdev
->dev
= &pdev
->dev
;
137 INIT_DELAYED_WORK(&wdev
->ping_work
, retu_wdt_ping_work
);
139 ret
= watchdog_register_device(retu_wdt
);
144 retu_wdt_ping(retu_wdt
);
146 retu_wdt_ping_enable(wdev
);
148 platform_set_drvdata(pdev
, retu_wdt
);
153 static int retu_wdt_remove(struct platform_device
*pdev
)
155 struct watchdog_device
*wdog
= platform_get_drvdata(pdev
);
156 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
158 watchdog_unregister_device(wdog
);
159 cancel_delayed_work_sync(&wdev
->ping_work
);
164 static struct platform_driver retu_wdt_driver
= {
165 .probe
= retu_wdt_probe
,
166 .remove
= retu_wdt_remove
,
171 module_platform_driver(retu_wdt_driver
);
173 MODULE_ALIAS("platform:retu-wdt");
174 MODULE_DESCRIPTION("Retu watchdog");
175 MODULE_AUTHOR("Amit Kucheria");
176 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
177 MODULE_LICENSE("GPL");