treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / watchdog / imx7ulp_wdt.c
blob11b9e7c6b7f596a3b5a28c4bfe7acf0e02bece85
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2019 NXP.
4 */
6 #include <linux/clk.h>
7 #include <linux/init.h>
8 #include <linux/io.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include <linux/reboot.h>
14 #include <linux/watchdog.h>
16 #define WDOG_CS 0x0
17 #define WDOG_CS_CMD32EN BIT(13)
18 #define WDOG_CS_ULK BIT(11)
19 #define WDOG_CS_RCS BIT(10)
20 #define LPO_CLK 0x1
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)
26 #define WDOG_CNT 0x4
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;
48 void __iomem *base;
49 struct clk *clk;
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);
59 if (enable)
60 writel(val | WDOG_CS_EN, wdt->base + WDOG_CS);
61 else
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);
78 return 0;
81 static int imx7ulp_wdt_start(struct watchdog_device *wdog)
84 imx7ulp_wdt_enable(wdog, true);
86 return 0;
89 static int imx7ulp_wdt_stop(struct watchdog_device *wdog)
91 imx7ulp_wdt_enable(wdog, false);
93 return 0;
96 static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog,
97 unsigned int timeout)
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;
107 return 0;
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 */
119 while (true)
122 return NOTIFY_DONE;
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 |
137 WDIOF_MAGICCLOSE,
140 static void imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)
142 u32 val;
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;
165 int ret;
167 imx7ulp_wdt = devm_kzalloc(dev, sizeof(*imx7ulp_wdt), GFP_KERNEL);
168 if (!imx7ulp_wdt)
169 return -ENOMEM;
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);
184 if (ret)
185 return ret;
187 ret = devm_add_action_or_reset(dev, imx7ulp_wdt_action, imx7ulp_wdt->clk);
188 if (ret)
189 return ret;
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;
196 wdog->parent = dev;
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);
217 return 0;
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;
224 int ret;
226 ret = clk_prepare_enable(imx7ulp_wdt->clk);
227 if (ret)
228 return ret;
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);
236 return 0;
239 static SIMPLE_DEV_PM_OPS(imx7ulp_wdt_pm_ops, imx7ulp_wdt_suspend,
240 imx7ulp_wdt_resume);
242 static const struct of_device_id imx7ulp_wdt_dt_ids[] = {
243 { .compatible = "fsl,imx7ulp-wdt", },
244 { /* sentinel */ }
246 MODULE_DEVICE_TABLE(of, imx7ulp_wdt_dt_ids);
248 static struct platform_driver imx7ulp_wdt_driver = {
249 .probe = imx7ulp_wdt_probe,
250 .driver = {
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");