1 // SPDX-License-Identifier: GPL-2.0
8 #include <linux/iopoll.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/reboot.h>
14 #include <linux/watchdog.h>
17 #define WDOG_CS_CMD32EN BIT(13)
18 #define WDOG_CS_ULK BIT(11)
19 #define WDOG_CS_RCS BIT(10)
21 #define LPO_CLK_SHIFT 8
22 #define WDOG_CS_CLK (LPO_CLK << LPO_CLK_SHIFT)
23 #define WDOG_CS_EN BIT(7)
24 #define WDOG_CS_UPDATE BIT(5)
25 #define WDOG_CS_WAIT BIT(1)
26 #define WDOG_CS_STOP BIT(0)
29 #define WDOG_TOVAL 0x8
31 #define REFRESH_SEQ0 0xA602
32 #define REFRESH_SEQ1 0xB480
33 #define REFRESH ((REFRESH_SEQ1 << 16) | REFRESH_SEQ0)
35 #define UNLOCK_SEQ0 0xC520
36 #define UNLOCK_SEQ1 0xD928
37 #define UNLOCK ((UNLOCK_SEQ1 << 16) | UNLOCK_SEQ0)
39 #define DEFAULT_TIMEOUT 60
40 #define MAX_TIMEOUT 128
41 #define WDOG_CLOCK_RATE 1000
42 #define WDOG_WAIT_TIMEOUT 20
44 static bool nowayout
= WATCHDOG_NOWAYOUT
;
45 module_param(nowayout
, bool, 0000);
46 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
47 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
49 struct imx7ulp_wdt_device
{
50 struct watchdog_device wdd
;
55 static int imx7ulp_wdt_wait(void __iomem
*base
, u32 mask
)
57 u32 val
= readl(base
+ WDOG_CS
);
59 if (!(val
& mask
) && readl_poll_timeout_atomic(base
+ WDOG_CS
, val
,
67 static int imx7ulp_wdt_enable(struct watchdog_device
*wdog
, bool enable
)
69 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
71 u32 val
= readl(wdt
->base
+ WDOG_CS
);
75 writel(UNLOCK
, wdt
->base
+ WDOG_CNT
);
76 ret
= imx7ulp_wdt_wait(wdt
->base
, WDOG_CS_ULK
);
80 writel(val
| WDOG_CS_EN
, wdt
->base
+ WDOG_CS
);
82 writel(val
& ~WDOG_CS_EN
, wdt
->base
+ WDOG_CS
);
83 imx7ulp_wdt_wait(wdt
->base
, WDOG_CS_RCS
);
91 static bool imx7ulp_wdt_is_enabled(void __iomem
*base
)
93 u32 val
= readl(base
+ WDOG_CS
);
95 return val
& WDOG_CS_EN
;
98 static int imx7ulp_wdt_ping(struct watchdog_device
*wdog
)
100 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
102 writel(REFRESH
, wdt
->base
+ WDOG_CNT
);
107 static int imx7ulp_wdt_start(struct watchdog_device
*wdog
)
109 return imx7ulp_wdt_enable(wdog
, true);
112 static int imx7ulp_wdt_stop(struct watchdog_device
*wdog
)
114 return imx7ulp_wdt_enable(wdog
, false);
117 static int imx7ulp_wdt_set_timeout(struct watchdog_device
*wdog
,
118 unsigned int timeout
)
120 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
121 u32 val
= WDOG_CLOCK_RATE
* timeout
;
125 writel(UNLOCK
, wdt
->base
+ WDOG_CNT
);
126 ret
= imx7ulp_wdt_wait(wdt
->base
, WDOG_CS_ULK
);
129 writel(val
, wdt
->base
+ WDOG_TOVAL
);
130 imx7ulp_wdt_wait(wdt
->base
, WDOG_CS_RCS
);
132 wdog
->timeout
= timeout
;
140 static int imx7ulp_wdt_restart(struct watchdog_device
*wdog
,
141 unsigned long action
, void *data
)
143 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
146 ret
= imx7ulp_wdt_enable(wdog
, true);
150 ret
= imx7ulp_wdt_set_timeout(&wdt
->wdd
, 1);
154 /* wait for wdog to fire */
161 static const struct watchdog_ops imx7ulp_wdt_ops
= {
162 .owner
= THIS_MODULE
,
163 .start
= imx7ulp_wdt_start
,
164 .stop
= imx7ulp_wdt_stop
,
165 .ping
= imx7ulp_wdt_ping
,
166 .set_timeout
= imx7ulp_wdt_set_timeout
,
167 .restart
= imx7ulp_wdt_restart
,
170 static const struct watchdog_info imx7ulp_wdt_info
= {
171 .identity
= "i.MX7ULP watchdog timer",
172 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
|
176 static int imx7ulp_wdt_init(void __iomem
*base
, unsigned int timeout
)
182 /* unlock the wdog for reconfiguration */
183 writel_relaxed(UNLOCK_SEQ0
, base
+ WDOG_CNT
);
184 writel_relaxed(UNLOCK_SEQ1
, base
+ WDOG_CNT
);
185 ret
= imx7ulp_wdt_wait(base
, WDOG_CS_ULK
);
189 /* set an initial timeout value in TOVAL */
190 writel(timeout
, base
+ WDOG_TOVAL
);
191 /* enable 32bit command sequence and reconfigure */
192 val
= WDOG_CS_CMD32EN
| WDOG_CS_CLK
| WDOG_CS_UPDATE
|
193 WDOG_CS_WAIT
| WDOG_CS_STOP
;
194 writel(val
, base
+ WDOG_CS
);
195 imx7ulp_wdt_wait(base
, WDOG_CS_RCS
);
203 static void imx7ulp_wdt_action(void *data
)
205 clk_disable_unprepare(data
);
208 static int imx7ulp_wdt_probe(struct platform_device
*pdev
)
210 struct imx7ulp_wdt_device
*imx7ulp_wdt
;
211 struct device
*dev
= &pdev
->dev
;
212 struct watchdog_device
*wdog
;
215 imx7ulp_wdt
= devm_kzalloc(dev
, sizeof(*imx7ulp_wdt
), GFP_KERNEL
);
219 platform_set_drvdata(pdev
, imx7ulp_wdt
);
221 imx7ulp_wdt
->base
= devm_platform_ioremap_resource(pdev
, 0);
222 if (IS_ERR(imx7ulp_wdt
->base
))
223 return PTR_ERR(imx7ulp_wdt
->base
);
225 imx7ulp_wdt
->clk
= devm_clk_get(dev
, NULL
);
226 if (IS_ERR(imx7ulp_wdt
->clk
)) {
227 dev_err(dev
, "Failed to get watchdog clock\n");
228 return PTR_ERR(imx7ulp_wdt
->clk
);
231 ret
= clk_prepare_enable(imx7ulp_wdt
->clk
);
235 ret
= devm_add_action_or_reset(dev
, imx7ulp_wdt_action
, imx7ulp_wdt
->clk
);
239 wdog
= &imx7ulp_wdt
->wdd
;
240 wdog
->info
= &imx7ulp_wdt_info
;
241 wdog
->ops
= &imx7ulp_wdt_ops
;
242 wdog
->min_timeout
= 1;
243 wdog
->max_timeout
= MAX_TIMEOUT
;
245 wdog
->timeout
= DEFAULT_TIMEOUT
;
247 watchdog_init_timeout(wdog
, 0, dev
);
248 watchdog_stop_on_reboot(wdog
);
249 watchdog_stop_on_unregister(wdog
);
250 watchdog_set_drvdata(wdog
, imx7ulp_wdt
);
251 ret
= imx7ulp_wdt_init(imx7ulp_wdt
->base
, wdog
->timeout
* WDOG_CLOCK_RATE
);
255 return devm_watchdog_register_device(dev
, wdog
);
258 static int __maybe_unused
imx7ulp_wdt_suspend(struct device
*dev
)
260 struct imx7ulp_wdt_device
*imx7ulp_wdt
= dev_get_drvdata(dev
);
262 if (watchdog_active(&imx7ulp_wdt
->wdd
))
263 imx7ulp_wdt_stop(&imx7ulp_wdt
->wdd
);
265 clk_disable_unprepare(imx7ulp_wdt
->clk
);
270 static int __maybe_unused
imx7ulp_wdt_resume(struct device
*dev
)
272 struct imx7ulp_wdt_device
*imx7ulp_wdt
= dev_get_drvdata(dev
);
273 u32 timeout
= imx7ulp_wdt
->wdd
.timeout
* WDOG_CLOCK_RATE
;
276 ret
= clk_prepare_enable(imx7ulp_wdt
->clk
);
280 if (imx7ulp_wdt_is_enabled(imx7ulp_wdt
->base
))
281 imx7ulp_wdt_init(imx7ulp_wdt
->base
, timeout
);
283 if (watchdog_active(&imx7ulp_wdt
->wdd
))
284 imx7ulp_wdt_start(&imx7ulp_wdt
->wdd
);
289 static SIMPLE_DEV_PM_OPS(imx7ulp_wdt_pm_ops
, imx7ulp_wdt_suspend
,
292 static const struct of_device_id imx7ulp_wdt_dt_ids
[] = {
293 { .compatible
= "fsl,imx7ulp-wdt", },
296 MODULE_DEVICE_TABLE(of
, imx7ulp_wdt_dt_ids
);
298 static struct platform_driver imx7ulp_wdt_driver
= {
299 .probe
= imx7ulp_wdt_probe
,
301 .name
= "imx7ulp-wdt",
302 .pm
= &imx7ulp_wdt_pm_ops
,
303 .of_match_table
= imx7ulp_wdt_dt_ids
,
306 module_platform_driver(imx7ulp_wdt_driver
);
308 MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
309 MODULE_DESCRIPTION("Freescale i.MX7ULP watchdog driver");
310 MODULE_LICENSE("GPL v2");