1 // SPDX-License-Identifier: GPL-2.0
7 #include <linux/init.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)
27 #define WDOG_TOVAL 0x8
29 #define REFRESH_SEQ0 0xA602
30 #define REFRESH_SEQ1 0xB480
31 #define REFRESH ((REFRESH_SEQ1 << 16) | REFRESH_SEQ0)
33 #define UNLOCK_SEQ0 0xC520
34 #define UNLOCK_SEQ1 0xD928
35 #define UNLOCK ((UNLOCK_SEQ1 << 16) | UNLOCK_SEQ0)
37 #define DEFAULT_TIMEOUT 60
38 #define MAX_TIMEOUT 128
39 #define WDOG_CLOCK_RATE 1000
41 static bool nowayout
= WATCHDOG_NOWAYOUT
;
42 module_param(nowayout
, bool, 0000);
43 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
44 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
46 struct imx7ulp_wdt_device
{
47 struct watchdog_device wdd
;
52 static void imx7ulp_wdt_enable(struct watchdog_device
*wdog
, bool enable
)
54 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
56 u32 val
= readl(wdt
->base
+ WDOG_CS
);
58 writel(UNLOCK
, wdt
->base
+ WDOG_CNT
);
60 writel(val
| WDOG_CS_EN
, wdt
->base
+ WDOG_CS
);
62 writel(val
& ~WDOG_CS_EN
, wdt
->base
+ WDOG_CS
);
65 static bool imx7ulp_wdt_is_enabled(void __iomem
*base
)
67 u32 val
= readl(base
+ WDOG_CS
);
69 return val
& WDOG_CS_EN
;
72 static int imx7ulp_wdt_ping(struct watchdog_device
*wdog
)
74 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
76 writel(REFRESH
, wdt
->base
+ WDOG_CNT
);
81 static int imx7ulp_wdt_start(struct watchdog_device
*wdog
)
84 imx7ulp_wdt_enable(wdog
, true);
89 static int imx7ulp_wdt_stop(struct watchdog_device
*wdog
)
91 imx7ulp_wdt_enable(wdog
, false);
96 static int imx7ulp_wdt_set_timeout(struct watchdog_device
*wdog
,
99 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
100 u32 val
= WDOG_CLOCK_RATE
* timeout
;
102 writel(UNLOCK
, wdt
->base
+ WDOG_CNT
);
103 writel(val
, wdt
->base
+ WDOG_TOVAL
);
105 wdog
->timeout
= timeout
;
110 static int imx7ulp_wdt_restart(struct watchdog_device
*wdog
,
111 unsigned long action
, void *data
)
113 struct imx7ulp_wdt_device
*wdt
= watchdog_get_drvdata(wdog
);
115 imx7ulp_wdt_enable(wdog
, true);
116 imx7ulp_wdt_set_timeout(&wdt
->wdd
, 1);
118 /* wait for wdog to fire */
125 static const struct watchdog_ops imx7ulp_wdt_ops
= {
126 .owner
= THIS_MODULE
,
127 .start
= imx7ulp_wdt_start
,
128 .stop
= imx7ulp_wdt_stop
,
129 .ping
= imx7ulp_wdt_ping
,
130 .set_timeout
= imx7ulp_wdt_set_timeout
,
131 .restart
= imx7ulp_wdt_restart
,
134 static const struct watchdog_info imx7ulp_wdt_info
= {
135 .identity
= "i.MX7ULP watchdog timer",
136 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
|
140 static void imx7ulp_wdt_init(void __iomem
*base
, unsigned int timeout
)
144 /* unlock the wdog for reconfiguration */
145 writel_relaxed(UNLOCK_SEQ0
, base
+ WDOG_CNT
);
146 writel_relaxed(UNLOCK_SEQ1
, base
+ WDOG_CNT
);
148 /* set an initial timeout value in TOVAL */
149 writel(timeout
, base
+ WDOG_TOVAL
);
150 /* enable 32bit command sequence and reconfigure */
151 val
= WDOG_CS_CMD32EN
| WDOG_CS_CLK
| WDOG_CS_UPDATE
;
152 writel(val
, base
+ WDOG_CS
);
155 static void imx7ulp_wdt_action(void *data
)
157 clk_disable_unprepare(data
);
160 static int imx7ulp_wdt_probe(struct platform_device
*pdev
)
162 struct imx7ulp_wdt_device
*imx7ulp_wdt
;
163 struct device
*dev
= &pdev
->dev
;
164 struct watchdog_device
*wdog
;
167 imx7ulp_wdt
= devm_kzalloc(dev
, sizeof(*imx7ulp_wdt
), GFP_KERNEL
);
171 platform_set_drvdata(pdev
, imx7ulp_wdt
);
173 imx7ulp_wdt
->base
= devm_platform_ioremap_resource(pdev
, 0);
174 if (IS_ERR(imx7ulp_wdt
->base
))
175 return PTR_ERR(imx7ulp_wdt
->base
);
177 imx7ulp_wdt
->clk
= devm_clk_get(dev
, NULL
);
178 if (IS_ERR(imx7ulp_wdt
->clk
)) {
179 dev_err(dev
, "Failed to get watchdog clock\n");
180 return PTR_ERR(imx7ulp_wdt
->clk
);
183 ret
= clk_prepare_enable(imx7ulp_wdt
->clk
);
187 ret
= devm_add_action_or_reset(dev
, imx7ulp_wdt_action
, imx7ulp_wdt
->clk
);
191 wdog
= &imx7ulp_wdt
->wdd
;
192 wdog
->info
= &imx7ulp_wdt_info
;
193 wdog
->ops
= &imx7ulp_wdt_ops
;
194 wdog
->min_timeout
= 1;
195 wdog
->max_timeout
= MAX_TIMEOUT
;
197 wdog
->timeout
= DEFAULT_TIMEOUT
;
199 watchdog_init_timeout(wdog
, 0, dev
);
200 watchdog_stop_on_reboot(wdog
);
201 watchdog_stop_on_unregister(wdog
);
202 watchdog_set_drvdata(wdog
, imx7ulp_wdt
);
203 imx7ulp_wdt_init(imx7ulp_wdt
->base
, wdog
->timeout
* WDOG_CLOCK_RATE
);
205 return devm_watchdog_register_device(dev
, wdog
);
208 static int __maybe_unused
imx7ulp_wdt_suspend(struct device
*dev
)
210 struct imx7ulp_wdt_device
*imx7ulp_wdt
= dev_get_drvdata(dev
);
212 if (watchdog_active(&imx7ulp_wdt
->wdd
))
213 imx7ulp_wdt_stop(&imx7ulp_wdt
->wdd
);
215 clk_disable_unprepare(imx7ulp_wdt
->clk
);
220 static int __maybe_unused
imx7ulp_wdt_resume(struct device
*dev
)
222 struct imx7ulp_wdt_device
*imx7ulp_wdt
= dev_get_drvdata(dev
);
223 u32 timeout
= imx7ulp_wdt
->wdd
.timeout
* WDOG_CLOCK_RATE
;
226 ret
= clk_prepare_enable(imx7ulp_wdt
->clk
);
230 if (imx7ulp_wdt_is_enabled(imx7ulp_wdt
->base
))
231 imx7ulp_wdt_init(imx7ulp_wdt
->base
, timeout
);
233 if (watchdog_active(&imx7ulp_wdt
->wdd
))
234 imx7ulp_wdt_start(&imx7ulp_wdt
->wdd
);
239 static SIMPLE_DEV_PM_OPS(imx7ulp_wdt_pm_ops
, imx7ulp_wdt_suspend
,
242 static const struct of_device_id imx7ulp_wdt_dt_ids
[] = {
243 { .compatible
= "fsl,imx7ulp-wdt", },
246 MODULE_DEVICE_TABLE(of
, imx7ulp_wdt_dt_ids
);
248 static struct platform_driver imx7ulp_wdt_driver
= {
249 .probe
= imx7ulp_wdt_probe
,
251 .name
= "imx7ulp-wdt",
252 .pm
= &imx7ulp_wdt_pm_ops
,
253 .of_match_table
= imx7ulp_wdt_dt_ids
,
256 module_platform_driver(imx7ulp_wdt_driver
);
258 MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
259 MODULE_DESCRIPTION("Freescale i.MX7ULP watchdog driver");
260 MODULE_LICENSE("GPL v2");