Skip to content

Commit e9800b7

Browse files
fifteenhexWim Van Sebroeck
authored andcommitted
watchdog: Add Mstar MSC313e WDT driver
It adds a driver for the IP block handling the watchdog timer found for Mstar MSC313e SoCs and newer. Signed-off-by: Daniel Palmer <[email protected]> Co-developed-by: Romain Perier <[email protected]> Signed-off-by: Romain Perier <[email protected]> Reviewed-by: Guenter Roeck <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Guenter Roeck <[email protected]> Signed-off-by: Wim Van Sebroeck <[email protected]>
1 parent 3e5fcb0 commit e9800b7

File tree

4 files changed

+180
-0
lines changed

4 files changed

+180
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,7 @@ F: arch/arm/boot/dts/mstar-*
21752175
F: arch/arm/mach-mstar/
21762176
F: drivers/clk/mstar/
21772177
F: drivers/gpio/gpio-msc313.c
2178+
F: drivers/watchdog/msc313e_wdt.c
21782179
F: include/dt-bindings/clock/mstar-*
21792180
F: include/dt-bindings/gpio/msc313-gpio.h
21802181

drivers/watchdog/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,18 @@ config VISCONTI_WATCHDOG
989989
Say Y here to include support for the watchdog timer in Toshiba
990990
Visconti SoCs.
991991

992+
config MSC313E_WATCHDOG
993+
tristate "MStar MSC313e watchdog"
994+
depends on ARCH_MSTARV7 || COMPILE_TEST
995+
select WATCHDOG_CORE
996+
help
997+
Say Y here to include support for the Watchdog timer embedded
998+
into MStar MSC313e chips. This will reboot your system when the
999+
timeout is reached.
1000+
1001+
To compile this driver as a module, choose M here: the
1002+
module will be called msc313e_wdt.
1003+
9921004
# X86 (i386 + ia64 + x86_64) Architecture
9931005

9941006
config ACQUIRE_WDT

drivers/watchdog/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o
9393
obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
9494
obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
9595
obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
96+
obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
9697

9798
# X86 (i386 + ia64 + x86_64) Architecture
9899
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o

drivers/watchdog/msc313e_wdt.c

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* MStar WDT driver
4+
*
5+
* Copyright (C) 2019 - 2021 Daniel Palmer
6+
* Copyright (C) 2021 Romain Perier
7+
*
8+
*/
9+
10+
#include <linux/clk.h>
11+
#include <linux/io.h>
12+
#include <linux/mod_devicetable.h>
13+
#include <linux/module.h>
14+
#include <linux/platform_device.h>
15+
#include <linux/watchdog.h>
16+
17+
#define REG_WDT_CLR 0x0
18+
#define REG_WDT_MAX_PRD_L 0x10
19+
#define REG_WDT_MAX_PRD_H 0x14
20+
21+
#define MSC313E_WDT_MIN_TIMEOUT 1
22+
#define MSC313E_WDT_DEFAULT_TIMEOUT 30
23+
24+
static unsigned int timeout;
25+
26+
module_param(timeout, int, 0);
27+
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
28+
29+
struct msc313e_wdt_priv {
30+
void __iomem *base;
31+
struct watchdog_device wdev;
32+
struct clk *clk;
33+
};
34+
35+
static int msc313e_wdt_start(struct watchdog_device *wdev)
36+
{
37+
struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
38+
u32 timeout;
39+
int err;
40+
41+
err = clk_prepare_enable(priv->clk);
42+
if (err)
43+
return err;
44+
45+
timeout = wdev->timeout * clk_get_rate(priv->clk);
46+
writew(timeout & 0xffff, priv->base + REG_WDT_MAX_PRD_L);
47+
writew((timeout >> 16) & 0xffff, priv->base + REG_WDT_MAX_PRD_H);
48+
writew(1, priv->base + REG_WDT_CLR);
49+
return 0;
50+
}
51+
52+
static int msc313e_wdt_ping(struct watchdog_device *wdev)
53+
{
54+
struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
55+
56+
writew(1, priv->base + REG_WDT_CLR);
57+
return 0;
58+
}
59+
60+
static int msc313e_wdt_stop(struct watchdog_device *wdev)
61+
{
62+
struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
63+
64+
writew(0, priv->base + REG_WDT_MAX_PRD_L);
65+
writew(0, priv->base + REG_WDT_MAX_PRD_H);
66+
writew(0, priv->base + REG_WDT_CLR);
67+
clk_disable_unprepare(priv->clk);
68+
return 0;
69+
}
70+
71+
static int msc313e_wdt_settimeout(struct watchdog_device *wdev, unsigned int new_time)
72+
{
73+
wdev->timeout = new_time;
74+
75+
return msc313e_wdt_start(wdev);
76+
}
77+
78+
static const struct watchdog_info msc313e_wdt_ident = {
79+
.identity = "MSC313e watchdog",
80+
.options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
81+
};
82+
83+
static const struct watchdog_ops msc313e_wdt_ops = {
84+
.owner = THIS_MODULE,
85+
.start = msc313e_wdt_start,
86+
.stop = msc313e_wdt_stop,
87+
.ping = msc313e_wdt_ping,
88+
.set_timeout = msc313e_wdt_settimeout,
89+
};
90+
91+
static const struct of_device_id msc313e_wdt_of_match[] = {
92+
{ .compatible = "mstar,msc313e-wdt", },
93+
{ /* sentinel */ }
94+
};
95+
MODULE_DEVICE_TABLE(of, msc313e_wdt_of_match);
96+
97+
static int msc313e_wdt_probe(struct platform_device *pdev)
98+
{
99+
struct device *dev = &pdev->dev;
100+
struct msc313e_wdt_priv *priv;
101+
102+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
103+
if (!priv)
104+
return -ENOMEM;
105+
106+
priv->base = devm_platform_ioremap_resource(pdev, 0);
107+
if (IS_ERR(priv->base))
108+
return PTR_ERR(priv->base);
109+
110+
priv->clk = devm_clk_get(dev, NULL);
111+
if (IS_ERR(priv->clk)) {
112+
dev_err(dev, "No input clock\n");
113+
return PTR_ERR(priv->clk);
114+
}
115+
116+
priv->wdev.info = &msc313e_wdt_ident,
117+
priv->wdev.ops = &msc313e_wdt_ops,
118+
priv->wdev.parent = dev;
119+
priv->wdev.min_timeout = MSC313E_WDT_MIN_TIMEOUT;
120+
priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);
121+
priv->wdev.timeout = MSC313E_WDT_DEFAULT_TIMEOUT;
122+
123+
watchdog_set_drvdata(&priv->wdev, priv);
124+
125+
watchdog_init_timeout(&priv->wdev, timeout, dev);
126+
watchdog_stop_on_reboot(&priv->wdev);
127+
watchdog_stop_on_unregister(&priv->wdev);
128+
129+
return devm_watchdog_register_device(dev, &priv->wdev);
130+
}
131+
132+
static int __maybe_unused msc313e_wdt_suspend(struct device *dev)
133+
{
134+
struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
135+
136+
if (watchdog_active(&priv->wdev))
137+
msc313e_wdt_stop(&priv->wdev);
138+
139+
return 0;
140+
}
141+
142+
static int __maybe_unused msc313e_wdt_resume(struct device *dev)
143+
{
144+
struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
145+
146+
if (watchdog_active(&priv->wdev))
147+
msc313e_wdt_start(&priv->wdev);
148+
149+
return 0;
150+
}
151+
152+
static SIMPLE_DEV_PM_OPS(msc313e_wdt_pm_ops, msc313e_wdt_suspend, msc313e_wdt_resume);
153+
154+
static struct platform_driver msc313e_wdt_driver = {
155+
.driver = {
156+
.name = "msc313e-wdt",
157+
.of_match_table = msc313e_wdt_of_match,
158+
.pm = &msc313e_wdt_pm_ops,
159+
},
160+
.probe = msc313e_wdt_probe,
161+
};
162+
module_platform_driver(msc313e_wdt_driver);
163+
164+
MODULE_AUTHOR("Daniel Palmer <[email protected]>");
165+
MODULE_DESCRIPTION("Watchdog driver for MStar MSC313e");
166+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)