1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Watchdog driver for IMX2 and later processors
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <kernel@pengutronix.de>
6*4882a593Smuzhiyun * Copyright (C) 2014 Freescale Semiconductor, Inc.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * some parts adapted by similar drivers from Darius Augulis and Vladimir
9*4882a593Smuzhiyun * Zapolskiy, additional improvements by Wim Van Sebroeck.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * NOTE: MX1 has a slightly different Watchdog than MX2 and later:
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * MX1: MX2+:
14*4882a593Smuzhiyun * ---- -----
15*4882a593Smuzhiyun * Registers: 32-bit 16-bit
16*4882a593Smuzhiyun * Stopable timer: Yes No
17*4882a593Smuzhiyun * Need to enable clk: No Yes
18*4882a593Smuzhiyun * Halt on suspend: Manual Can be automatic
19*4882a593Smuzhiyun */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/clk.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/interrupt.h>
25*4882a593Smuzhiyun #include <linux/io.h>
26*4882a593Smuzhiyun #include <linux/kernel.h>
27*4882a593Smuzhiyun #include <linux/module.h>
28*4882a593Smuzhiyun #include <linux/moduleparam.h>
29*4882a593Smuzhiyun #include <linux/of_address.h>
30*4882a593Smuzhiyun #include <linux/platform_device.h>
31*4882a593Smuzhiyun #include <linux/regmap.h>
32*4882a593Smuzhiyun #include <linux/watchdog.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define DRIVER_NAME "imx2-wdt"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define IMX2_WDT_WCR 0x00 /* Control Register */
37*4882a593Smuzhiyun #define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */
38*4882a593Smuzhiyun #define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */
39*4882a593Smuzhiyun #define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */
40*4882a593Smuzhiyun #define IMX2_WDT_WCR_WRE BIT(3) /* -> WDOG Reset Enable */
41*4882a593Smuzhiyun #define IMX2_WDT_WCR_WDE BIT(2) /* -> Watchdog Enable */
42*4882a593Smuzhiyun #define IMX2_WDT_WCR_WDZST BIT(0) /* -> Watchdog timer Suspend */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define IMX2_WDT_WSR 0x02 /* Service Register */
45*4882a593Smuzhiyun #define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */
46*4882a593Smuzhiyun #define IMX2_WDT_SEQ2 0xAAAA /* -> service sequence 2 */
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #define IMX2_WDT_WRSR 0x04 /* Reset Status Register */
49*4882a593Smuzhiyun #define IMX2_WDT_WRSR_TOUT BIT(1) /* -> Reset due to Timeout */
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #define IMX2_WDT_WICR 0x06 /* Interrupt Control Register */
52*4882a593Smuzhiyun #define IMX2_WDT_WICR_WIE BIT(15) /* -> Interrupt Enable */
53*4882a593Smuzhiyun #define IMX2_WDT_WICR_WTIS BIT(14) /* -> Interrupt Status */
54*4882a593Smuzhiyun #define IMX2_WDT_WICR_WICT 0xFF /* -> Interrupt Count Timeout */
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #define IMX2_WDT_WMCR 0x08 /* Misc Register */
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define IMX2_WDT_MAX_TIME 128U
59*4882a593Smuzhiyun #define IMX2_WDT_DEFAULT_TIME 60 /* in seconds */
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun #define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun struct imx2_wdt_device {
64*4882a593Smuzhiyun struct clk *clk;
65*4882a593Smuzhiyun struct regmap *regmap;
66*4882a593Smuzhiyun struct watchdog_device wdog;
67*4882a593Smuzhiyun bool ext_reset;
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun static bool nowayout = WATCHDOG_NOWAYOUT;
71*4882a593Smuzhiyun module_param(nowayout, bool, 0);
72*4882a593Smuzhiyun MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
73*4882a593Smuzhiyun __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun static unsigned timeout;
76*4882a593Smuzhiyun module_param(timeout, uint, 0);
77*4882a593Smuzhiyun MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
78*4882a593Smuzhiyun __MODULE_STRING(IMX2_WDT_DEFAULT_TIME) ")");
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun static const struct watchdog_info imx2_wdt_info = {
81*4882a593Smuzhiyun .identity = "imx2+ watchdog",
82*4882a593Smuzhiyun .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static const struct watchdog_info imx2_wdt_pretimeout_info = {
86*4882a593Smuzhiyun .identity = "imx2+ watchdog",
87*4882a593Smuzhiyun .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
88*4882a593Smuzhiyun WDIOF_PRETIMEOUT,
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
imx2_wdt_restart(struct watchdog_device * wdog,unsigned long action,void * data)91*4882a593Smuzhiyun static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action,
92*4882a593Smuzhiyun void *data)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
95*4882a593Smuzhiyun unsigned int wcr_enable = IMX2_WDT_WCR_WDE;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /* Use internal reset or external - not both */
98*4882a593Smuzhiyun if (wdev->ext_reset)
99*4882a593Smuzhiyun wcr_enable |= IMX2_WDT_WCR_SRS; /* do not assert int reset */
100*4882a593Smuzhiyun else
101*4882a593Smuzhiyun wcr_enable |= IMX2_WDT_WCR_WDA; /* do not assert ext-reset */
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /* Assert SRS signal */
104*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
105*4882a593Smuzhiyun /*
106*4882a593Smuzhiyun * Due to imx6q errata ERR004346 (WDOG: WDOG SRS bit requires to be
107*4882a593Smuzhiyun * written twice), we add another two writes to ensure there must be at
108*4882a593Smuzhiyun * least two writes happen in the same one 32kHz clock period. We save
109*4882a593Smuzhiyun * the target check here, since the writes shouldn't be a huge burden
110*4882a593Smuzhiyun * for other platforms.
111*4882a593Smuzhiyun */
112*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
113*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* wait for reset to assert... */
116*4882a593Smuzhiyun mdelay(500);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun return 0;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
imx2_wdt_setup(struct watchdog_device * wdog)121*4882a593Smuzhiyun static inline void imx2_wdt_setup(struct watchdog_device *wdog)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
124*4882a593Smuzhiyun u32 val;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* Suspend timer in low power mode, write once-only */
129*4882a593Smuzhiyun val |= IMX2_WDT_WCR_WDZST;
130*4882a593Smuzhiyun /* Strip the old watchdog Time-Out value */
131*4882a593Smuzhiyun val &= ~IMX2_WDT_WCR_WT;
132*4882a593Smuzhiyun /* Generate internal chip-level reset if WDOG times out */
133*4882a593Smuzhiyun if (!wdev->ext_reset)
134*4882a593Smuzhiyun val &= ~IMX2_WDT_WCR_WRE;
135*4882a593Smuzhiyun /* Or if external-reset assert WDOG_B reset only on time-out */
136*4882a593Smuzhiyun else
137*4882a593Smuzhiyun val |= IMX2_WDT_WCR_WRE;
138*4882a593Smuzhiyun /* Keep Watchdog Disabled */
139*4882a593Smuzhiyun val &= ~IMX2_WDT_WCR_WDE;
140*4882a593Smuzhiyun /* Set the watchdog's Time-Out value */
141*4882a593Smuzhiyun val |= WDOG_SEC_TO_COUNT(wdog->timeout);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /* enable the watchdog */
146*4882a593Smuzhiyun val |= IMX2_WDT_WCR_WDE;
147*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
imx2_wdt_is_running(struct imx2_wdt_device * wdev)150*4882a593Smuzhiyun static inline bool imx2_wdt_is_running(struct imx2_wdt_device *wdev)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun u32 val;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun return val & IMX2_WDT_WCR_WDE;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
imx2_wdt_ping(struct watchdog_device * wdog)159*4882a593Smuzhiyun static int imx2_wdt_ping(struct watchdog_device *wdog)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
164*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
165*4882a593Smuzhiyun return 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
__imx2_wdt_set_timeout(struct watchdog_device * wdog,unsigned int new_timeout)168*4882a593Smuzhiyun static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
169*4882a593Smuzhiyun unsigned int new_timeout)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
174*4882a593Smuzhiyun WDOG_SEC_TO_COUNT(new_timeout));
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
imx2_wdt_set_timeout(struct watchdog_device * wdog,unsigned int new_timeout)177*4882a593Smuzhiyun static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
178*4882a593Smuzhiyun unsigned int new_timeout)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun unsigned int actual;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun actual = min(new_timeout, IMX2_WDT_MAX_TIME);
183*4882a593Smuzhiyun __imx2_wdt_set_timeout(wdog, actual);
184*4882a593Smuzhiyun wdog->timeout = new_timeout;
185*4882a593Smuzhiyun return 0;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
imx2_wdt_set_pretimeout(struct watchdog_device * wdog,unsigned int new_pretimeout)188*4882a593Smuzhiyun static int imx2_wdt_set_pretimeout(struct watchdog_device *wdog,
189*4882a593Smuzhiyun unsigned int new_pretimeout)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (new_pretimeout >= IMX2_WDT_MAX_TIME)
194*4882a593Smuzhiyun return -EINVAL;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun wdog->pretimeout = new_pretimeout;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun regmap_update_bits(wdev->regmap, IMX2_WDT_WICR,
199*4882a593Smuzhiyun IMX2_WDT_WICR_WIE | IMX2_WDT_WICR_WICT,
200*4882a593Smuzhiyun IMX2_WDT_WICR_WIE | (new_pretimeout << 1));
201*4882a593Smuzhiyun return 0;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
imx2_wdt_isr(int irq,void * wdog_arg)204*4882a593Smuzhiyun static irqreturn_t imx2_wdt_isr(int irq, void *wdog_arg)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun struct watchdog_device *wdog = wdog_arg;
207*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun regmap_write_bits(wdev->regmap, IMX2_WDT_WICR,
210*4882a593Smuzhiyun IMX2_WDT_WICR_WTIS, IMX2_WDT_WICR_WTIS);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun watchdog_notify_pretimeout(wdog);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun return IRQ_HANDLED;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
imx2_wdt_start(struct watchdog_device * wdog)217*4882a593Smuzhiyun static int imx2_wdt_start(struct watchdog_device *wdog)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (imx2_wdt_is_running(wdev))
222*4882a593Smuzhiyun imx2_wdt_set_timeout(wdog, wdog->timeout);
223*4882a593Smuzhiyun else
224*4882a593Smuzhiyun imx2_wdt_setup(wdog);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun set_bit(WDOG_HW_RUNNING, &wdog->status);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun return imx2_wdt_ping(wdog);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun static const struct watchdog_ops imx2_wdt_ops = {
232*4882a593Smuzhiyun .owner = THIS_MODULE,
233*4882a593Smuzhiyun .start = imx2_wdt_start,
234*4882a593Smuzhiyun .ping = imx2_wdt_ping,
235*4882a593Smuzhiyun .set_timeout = imx2_wdt_set_timeout,
236*4882a593Smuzhiyun .set_pretimeout = imx2_wdt_set_pretimeout,
237*4882a593Smuzhiyun .restart = imx2_wdt_restart,
238*4882a593Smuzhiyun };
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun static const struct regmap_config imx2_wdt_regmap_config = {
241*4882a593Smuzhiyun .reg_bits = 16,
242*4882a593Smuzhiyun .reg_stride = 2,
243*4882a593Smuzhiyun .val_bits = 16,
244*4882a593Smuzhiyun .max_register = 0x8,
245*4882a593Smuzhiyun };
246*4882a593Smuzhiyun
imx2_wdt_action(void * data)247*4882a593Smuzhiyun static void imx2_wdt_action(void *data)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun clk_disable_unprepare(data);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
imx2_wdt_probe(struct platform_device * pdev)252*4882a593Smuzhiyun static int __init imx2_wdt_probe(struct platform_device *pdev)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun struct device *dev = &pdev->dev;
255*4882a593Smuzhiyun struct imx2_wdt_device *wdev;
256*4882a593Smuzhiyun struct watchdog_device *wdog;
257*4882a593Smuzhiyun void __iomem *base;
258*4882a593Smuzhiyun int ret;
259*4882a593Smuzhiyun u32 val;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun wdev = devm_kzalloc(dev, sizeof(*wdev), GFP_KERNEL);
262*4882a593Smuzhiyun if (!wdev)
263*4882a593Smuzhiyun return -ENOMEM;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun base = devm_platform_ioremap_resource(pdev, 0);
266*4882a593Smuzhiyun if (IS_ERR(base))
267*4882a593Smuzhiyun return PTR_ERR(base);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun wdev->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
270*4882a593Smuzhiyun &imx2_wdt_regmap_config);
271*4882a593Smuzhiyun if (IS_ERR(wdev->regmap)) {
272*4882a593Smuzhiyun dev_err(dev, "regmap init failed\n");
273*4882a593Smuzhiyun return PTR_ERR(wdev->regmap);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun wdev->clk = devm_clk_get(dev, NULL);
277*4882a593Smuzhiyun if (IS_ERR(wdev->clk)) {
278*4882a593Smuzhiyun dev_err(dev, "can't get Watchdog clock\n");
279*4882a593Smuzhiyun return PTR_ERR(wdev->clk);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun wdog = &wdev->wdog;
283*4882a593Smuzhiyun wdog->info = &imx2_wdt_info;
284*4882a593Smuzhiyun wdog->ops = &imx2_wdt_ops;
285*4882a593Smuzhiyun wdog->min_timeout = 1;
286*4882a593Smuzhiyun wdog->timeout = IMX2_WDT_DEFAULT_TIME;
287*4882a593Smuzhiyun wdog->max_hw_heartbeat_ms = IMX2_WDT_MAX_TIME * 1000;
288*4882a593Smuzhiyun wdog->parent = dev;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun ret = platform_get_irq(pdev, 0);
291*4882a593Smuzhiyun if (ret > 0)
292*4882a593Smuzhiyun if (!devm_request_irq(dev, ret, imx2_wdt_isr, 0,
293*4882a593Smuzhiyun dev_name(dev), wdog))
294*4882a593Smuzhiyun wdog->info = &imx2_wdt_pretimeout_info;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun ret = clk_prepare_enable(wdev->clk);
297*4882a593Smuzhiyun if (ret)
298*4882a593Smuzhiyun return ret;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun ret = devm_add_action_or_reset(dev, imx2_wdt_action, wdev->clk);
301*4882a593Smuzhiyun if (ret)
302*4882a593Smuzhiyun return ret;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val);
305*4882a593Smuzhiyun wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun wdev->ext_reset = of_property_read_bool(dev->of_node,
308*4882a593Smuzhiyun "fsl,ext-reset-output");
309*4882a593Smuzhiyun platform_set_drvdata(pdev, wdog);
310*4882a593Smuzhiyun watchdog_set_drvdata(wdog, wdev);
311*4882a593Smuzhiyun watchdog_set_nowayout(wdog, nowayout);
312*4882a593Smuzhiyun watchdog_set_restart_priority(wdog, 128);
313*4882a593Smuzhiyun watchdog_init_timeout(wdog, timeout, dev);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun if (imx2_wdt_is_running(wdev)) {
316*4882a593Smuzhiyun imx2_wdt_set_timeout(wdog, wdog->timeout);
317*4882a593Smuzhiyun set_bit(WDOG_HW_RUNNING, &wdog->status);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /*
321*4882a593Smuzhiyun * Disable the watchdog power down counter at boot. Otherwise the power
322*4882a593Smuzhiyun * down counter will pull down the #WDOG interrupt line for one clock
323*4882a593Smuzhiyun * cycle.
324*4882a593Smuzhiyun */
325*4882a593Smuzhiyun regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun return devm_watchdog_register_device(dev, wdog);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
imx2_wdt_shutdown(struct platform_device * pdev)330*4882a593Smuzhiyun static void imx2_wdt_shutdown(struct platform_device *pdev)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun struct watchdog_device *wdog = platform_get_drvdata(pdev);
333*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (imx2_wdt_is_running(wdev)) {
336*4882a593Smuzhiyun /*
337*4882a593Smuzhiyun * We are running, configure max timeout before reboot
338*4882a593Smuzhiyun * will take place.
339*4882a593Smuzhiyun */
340*4882a593Smuzhiyun imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
341*4882a593Smuzhiyun imx2_wdt_ping(wdog);
342*4882a593Smuzhiyun dev_crit(&pdev->dev, "Device shutdown: Expect reboot!\n");
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* Disable watchdog if it is active or non-active but still running */
imx2_wdt_suspend(struct device * dev)347*4882a593Smuzhiyun static int __maybe_unused imx2_wdt_suspend(struct device *dev)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun struct watchdog_device *wdog = dev_get_drvdata(dev);
350*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun /* The watchdog IP block is running */
353*4882a593Smuzhiyun if (imx2_wdt_is_running(wdev)) {
354*4882a593Smuzhiyun /*
355*4882a593Smuzhiyun * Don't update wdog->timeout, we'll restore the current value
356*4882a593Smuzhiyun * during resume.
357*4882a593Smuzhiyun */
358*4882a593Smuzhiyun __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
359*4882a593Smuzhiyun imx2_wdt_ping(wdog);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun clk_disable_unprepare(wdev->clk);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /* Enable watchdog and configure it if necessary */
imx2_wdt_resume(struct device * dev)368*4882a593Smuzhiyun static int __maybe_unused imx2_wdt_resume(struct device *dev)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun struct watchdog_device *wdog = dev_get_drvdata(dev);
371*4882a593Smuzhiyun struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
372*4882a593Smuzhiyun int ret;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun ret = clk_prepare_enable(wdev->clk);
375*4882a593Smuzhiyun if (ret)
376*4882a593Smuzhiyun return ret;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) {
379*4882a593Smuzhiyun /*
380*4882a593Smuzhiyun * If the watchdog is still active and resumes
381*4882a593Smuzhiyun * from deep sleep state, need to restart the
382*4882a593Smuzhiyun * watchdog again.
383*4882a593Smuzhiyun */
384*4882a593Smuzhiyun imx2_wdt_setup(wdog);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun if (imx2_wdt_is_running(wdev)) {
387*4882a593Smuzhiyun imx2_wdt_set_timeout(wdog, wdog->timeout);
388*4882a593Smuzhiyun imx2_wdt_ping(wdog);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun return 0;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
395*4882a593Smuzhiyun imx2_wdt_resume);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun static const struct of_device_id imx2_wdt_dt_ids[] = {
398*4882a593Smuzhiyun { .compatible = "fsl,imx21-wdt", },
399*4882a593Smuzhiyun { /* sentinel */ }
400*4882a593Smuzhiyun };
401*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun static struct platform_driver imx2_wdt_driver = {
404*4882a593Smuzhiyun .shutdown = imx2_wdt_shutdown,
405*4882a593Smuzhiyun .driver = {
406*4882a593Smuzhiyun .name = DRIVER_NAME,
407*4882a593Smuzhiyun .pm = &imx2_wdt_pm_ops,
408*4882a593Smuzhiyun .of_match_table = imx2_wdt_dt_ids,
409*4882a593Smuzhiyun },
410*4882a593Smuzhiyun };
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun module_platform_driver_probe(imx2_wdt_driver, imx2_wdt_probe);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun MODULE_AUTHOR("Wolfram Sang");
415*4882a593Smuzhiyun MODULE_DESCRIPTION("Watchdog driver for IMX2 and later");
416*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
417*4882a593Smuzhiyun MODULE_ALIAS("platform:" DRIVER_NAME);
418