1 Add a watchdog driver for ARM MPcore processors.
3 Signed-off-by: Felix Fietkau <nbd@nbd.name>
5 --- a/drivers/watchdog/Kconfig
6 +++ b/drivers/watchdog/Kconfig
7 @@ -324,6 +324,13 @@ config KS8695_WATCHDOG
8 Watchdog timer embedded into KS8695 processor. This will reboot your
9 system when the timeout is reached.
11 +config MPCORE_WATCHDOG
12 + tristate "MPcore watchdog"
13 + depends on HAVE_ARM_TWD
14 + select WATCHDOG_CORE
16 + Watchdog timer embedded into the MPcore system
18 config HAVE_S3C2410_WATCHDOG
21 --- a/drivers/watchdog/Makefile
22 +++ b/drivers/watchdog/Makefile
23 @@ -47,6 +47,7 @@ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
24 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
25 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
26 obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
27 +obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
28 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
29 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
30 obj-$(CONFIG_SAMA5D4_WATCHDOG) += sama5d4_wdt.o
32 +++ b/drivers/watchdog/mpcore_wdt.c
35 + * Watchdog driver for ARM MPcore
37 + * Copyright (C) 2017 Felix Fietkau <nbd@nbd.name>
40 +#include <linux/module.h>
41 +#include <linux/kernel.h>
42 +#include <linux/watchdog.h>
43 +#include <linux/platform_device.h>
44 +#include <linux/io.h>
45 +#include <asm/smp_twd.h>
47 +static void __iomem *wdt_base;
48 +static int wdt_timeout = 60;
50 +static int mpcore_wdt_keepalive(struct watchdog_device *wdd)
55 + count = ioread32(wdt_base + TWD_WDOG_COUNTER);
56 + count = (~0U - count) * HZ / 5;
57 + count /= 256; /* prescale */
58 + count *= wdt_timeout;
60 + /* Reload register needs a different value on each refresh */
64 + iowrite32(count, wdt_base + TWD_WDOG_LOAD);
69 +static int mpcore_wdt_start(struct watchdog_device *wdd)
71 + mpcore_wdt_keepalive(wdd);
73 + /* prescale = 256, mode = 1, enable = 1 */
74 + iowrite32(0x0000FF09, wdt_base + TWD_WDOG_CONTROL);
79 +static int mpcore_wdt_stop(struct watchdog_device *wdd)
81 + iowrite32(0x12345678, wdt_base + TWD_WDOG_DISABLE);
82 + iowrite32(0x87654321, wdt_base + TWD_WDOG_DISABLE);
83 + iowrite32(0x0, wdt_base + TWD_WDOG_CONTROL);
88 +static int mpcore_wdt_set_timeout(struct watchdog_device *wdd,
89 + unsigned int timeout)
91 + mpcore_wdt_stop(wdd);
92 + wdt_timeout = timeout;
93 + mpcore_wdt_start(wdd);
98 +static const struct watchdog_info mpcore_wdt_info = {
99 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
100 + .identity = "MPcore Watchdog",
103 +static const struct watchdog_ops mpcore_wdt_ops = {
104 + .owner = THIS_MODULE,
105 + .start = mpcore_wdt_start,
106 + .stop = mpcore_wdt_stop,
107 + .ping = mpcore_wdt_keepalive,
108 + .set_timeout = mpcore_wdt_set_timeout,
111 +static struct watchdog_device mpcore_wdt = {
112 + .info = &mpcore_wdt_info,
113 + .ops = &mpcore_wdt_ops,
115 + .max_timeout = 65535,
118 +static int mpcore_wdt_probe(struct platform_device *pdev)
120 + struct resource *res;
122 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
126 + wdt_base = devm_ioremap_resource(&pdev->dev, res);
127 + if (IS_ERR(wdt_base))
128 + return PTR_ERR(wdt_base);
130 + watchdog_register_device(&mpcore_wdt);
134 +static int mpcore_wdt_remove(struct platform_device *dev)
136 + watchdog_unregister_device(&mpcore_wdt);
140 +static struct platform_driver mpcore_wdt_driver = {
141 + .probe = mpcore_wdt_probe,
142 + .remove = mpcore_wdt_remove,
144 + .name = "mpcore_wdt",
148 +module_platform_driver(mpcore_wdt_driver);
149 +MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
150 +MODULE_LICENSE("GPL");