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/init.h>
20 #include <linux/slab.h>
21 #include <linux/errno.h>
22 #include <linux/device.h>
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/mfd/retu.h>
26 #include <linux/watchdog.h>
27 #include <linux/platform_device.h>
29 /* Watchdog timer values in seconds */
30 #define RETU_WDT_MAX_TIMER 63
33 struct retu_dev
*rdev
;
35 struct delayed_work ping_work
;
39 * Since Retu watchdog cannot be disabled in hardware, we must kick it
40 * with a timer until userspace watchdog software takes over. If
41 * CONFIG_WATCHDOG_NOWAYOUT is set, we never start the feeding.
43 static void retu_wdt_ping_enable(struct retu_wdt_dev
*wdev
)
45 retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, RETU_WDT_MAX_TIMER
);
46 schedule_delayed_work(&wdev
->ping_work
,
47 round_jiffies_relative(RETU_WDT_MAX_TIMER
* HZ
/ 2));
50 static void retu_wdt_ping_disable(struct retu_wdt_dev
*wdev
)
52 retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, RETU_WDT_MAX_TIMER
);
53 cancel_delayed_work_sync(&wdev
->ping_work
);
56 static void retu_wdt_ping_work(struct work_struct
*work
)
58 struct retu_wdt_dev
*wdev
= container_of(to_delayed_work(work
),
59 struct retu_wdt_dev
, ping_work
);
60 retu_wdt_ping_enable(wdev
);
63 static int retu_wdt_start(struct watchdog_device
*wdog
)
65 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
67 retu_wdt_ping_disable(wdev
);
69 return retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, wdog
->timeout
);
72 static int retu_wdt_stop(struct watchdog_device
*wdog
)
74 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
76 retu_wdt_ping_enable(wdev
);
81 static int retu_wdt_ping(struct watchdog_device
*wdog
)
83 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
85 return retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, wdog
->timeout
);
88 static int retu_wdt_set_timeout(struct watchdog_device
*wdog
,
91 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
93 wdog
->timeout
= timeout
;
94 return retu_write(wdev
->rdev
, RETU_REG_WATCHDOG
, wdog
->timeout
);
97 static const struct watchdog_info retu_wdt_info
= {
98 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
,
99 .identity
= "Retu watchdog",
102 static const struct watchdog_ops retu_wdt_ops
= {
103 .owner
= THIS_MODULE
,
104 .start
= retu_wdt_start
,
105 .stop
= retu_wdt_stop
,
106 .ping
= retu_wdt_ping
,
107 .set_timeout
= retu_wdt_set_timeout
,
110 static int retu_wdt_probe(struct platform_device
*pdev
)
112 struct retu_dev
*rdev
= dev_get_drvdata(pdev
->dev
.parent
);
113 bool nowayout
= WATCHDOG_NOWAYOUT
;
114 struct watchdog_device
*retu_wdt
;
115 struct retu_wdt_dev
*wdev
;
118 retu_wdt
= devm_kzalloc(&pdev
->dev
, sizeof(*retu_wdt
), GFP_KERNEL
);
122 wdev
= devm_kzalloc(&pdev
->dev
, sizeof(*wdev
), GFP_KERNEL
);
126 retu_wdt
->info
= &retu_wdt_info
;
127 retu_wdt
->ops
= &retu_wdt_ops
;
128 retu_wdt
->timeout
= RETU_WDT_MAX_TIMER
;
129 retu_wdt
->min_timeout
= 0;
130 retu_wdt
->max_timeout
= RETU_WDT_MAX_TIMER
;
132 watchdog_set_drvdata(retu_wdt
, wdev
);
133 watchdog_set_nowayout(retu_wdt
, nowayout
);
136 wdev
->dev
= &pdev
->dev
;
138 INIT_DELAYED_WORK(&wdev
->ping_work
, retu_wdt_ping_work
);
140 ret
= watchdog_register_device(retu_wdt
);
145 retu_wdt_ping(retu_wdt
);
147 retu_wdt_ping_enable(wdev
);
149 platform_set_drvdata(pdev
, retu_wdt
);
154 static int retu_wdt_remove(struct platform_device
*pdev
)
156 struct watchdog_device
*wdog
= platform_get_drvdata(pdev
);
157 struct retu_wdt_dev
*wdev
= watchdog_get_drvdata(wdog
);
159 watchdog_unregister_device(wdog
);
160 cancel_delayed_work_sync(&wdev
->ping_work
);
165 static struct platform_driver retu_wdt_driver
= {
166 .probe
= retu_wdt_probe
,
167 .remove
= retu_wdt_remove
,
172 module_platform_driver(retu_wdt_driver
);
174 MODULE_ALIAS("platform:retu-wdt");
175 MODULE_DESCRIPTION("Retu watchdog");
176 MODULE_AUTHOR("Amit Kucheria");
177 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
178 MODULE_LICENSE("GPL");