1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/watchdog.h>
11 /* Loongson 1 Watchdog Register Definitions */
16 #define DEFAULT_HEARTBEAT 30
18 static bool nowayout = WATCHDOG_NOWAYOUT;
19 module_param(nowayout, bool, 0444);
21 static unsigned int heartbeat;
22 module_param(heartbeat, uint, 0444);
24 struct ls1x_wdt_drvdata {
27 unsigned long clk_rate;
28 struct watchdog_device wdt;
31 static int ls1x_wdt_ping(struct watchdog_device *wdt_dev)
33 struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
35 writel(0x1, drvdata->base + WDT_SET);
40 static int ls1x_wdt_set_timeout(struct watchdog_device *wdt_dev,
43 struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
44 unsigned int max_hw_heartbeat = wdt_dev->max_hw_heartbeat_ms / 1000;
47 wdt_dev->timeout = timeout;
49 counts = drvdata->clk_rate * min(timeout, max_hw_heartbeat);
50 writel(counts, drvdata->base + WDT_TIMER);
55 static int ls1x_wdt_start(struct watchdog_device *wdt_dev)
57 struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
59 writel(0x1, drvdata->base + WDT_EN);
64 static int ls1x_wdt_stop(struct watchdog_device *wdt_dev)
66 struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
68 writel(0x0, drvdata->base + WDT_EN);
73 static int ls1x_wdt_restart(struct watchdog_device *wdt_dev,
74 unsigned long action, void *data)
76 struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
78 writel(0x1, drvdata->base + WDT_EN);
79 writel(0x1, drvdata->base + WDT_TIMER);
80 writel(0x1, drvdata->base + WDT_SET);
85 static const struct watchdog_info ls1x_wdt_info = {
86 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
87 .identity = "Loongson1 Watchdog",
90 static const struct watchdog_ops ls1x_wdt_ops = {
92 .start = ls1x_wdt_start,
93 .stop = ls1x_wdt_stop,
94 .ping = ls1x_wdt_ping,
95 .set_timeout = ls1x_wdt_set_timeout,
96 .restart = ls1x_wdt_restart,
99 static int ls1x_wdt_probe(struct platform_device *pdev)
101 struct device *dev = &pdev->dev;
102 struct ls1x_wdt_drvdata *drvdata;
103 struct watchdog_device *ls1x_wdt;
104 unsigned long clk_rate;
107 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
111 drvdata->base = devm_platform_ioremap_resource(pdev, 0);
112 if (IS_ERR(drvdata->base))
113 return PTR_ERR(drvdata->base);
115 drvdata->clk = devm_clk_get_enabled(dev, pdev->name);
116 if (IS_ERR(drvdata->clk))
117 return PTR_ERR(drvdata->clk);
119 clk_rate = clk_get_rate(drvdata->clk);
122 drvdata->clk_rate = clk_rate;
124 ls1x_wdt = &drvdata->wdt;
125 ls1x_wdt->info = &ls1x_wdt_info;
126 ls1x_wdt->ops = &ls1x_wdt_ops;
127 ls1x_wdt->timeout = DEFAULT_HEARTBEAT;
128 ls1x_wdt->min_timeout = 1;
129 ls1x_wdt->max_hw_heartbeat_ms = U32_MAX / clk_rate * 1000;
130 ls1x_wdt->parent = dev;
132 watchdog_init_timeout(ls1x_wdt, heartbeat, dev);
133 watchdog_set_nowayout(ls1x_wdt, nowayout);
134 watchdog_set_drvdata(ls1x_wdt, drvdata);
136 err = devm_watchdog_register_device(dev, &drvdata->wdt);
140 platform_set_drvdata(pdev, drvdata);
142 dev_info(dev, "Loongson1 Watchdog driver registered\n");
147 static struct platform_driver ls1x_wdt_driver = {
148 .probe = ls1x_wdt_probe,
154 module_platform_driver(ls1x_wdt_driver);
156 MODULE_AUTHOR("Yang Ling <gnaygnil@gmail.com>");
157 MODULE_DESCRIPTION("Loongson1 Watchdog Driver");
158 MODULE_LICENSE("GPL");