cns3xxx: refresh patches
[openwrt/staging/wigyori.git] / target / linux / cns3xxx / patches-4.14 / 020-watchdog_support.patch
1 Add a watchdog driver for ARM MPcore processors.
2
3 Signed-off-by: Felix Fietkau <nbd@nbd.name>
4 ---
5 --- a/drivers/watchdog/Kconfig
6 +++ b/drivers/watchdog/Kconfig
7 @@ -355,6 +355,13 @@ config KS8695_WATCHDOG
8 Watchdog timer embedded into KS8695 processor. This will reboot your
9 system when the timeout is reached.
10
11 +config MPCORE_WATCHDOG
12 + tristate "MPcore watchdog"
13 + depends on HAVE_ARM_TWD
14 + select WATCHDOG_CORE
15 + help
16 + Watchdog timer embedded into the MPcore system
17 +
18 config HAVE_S3C2410_WATCHDOG
19 bool
20 help
21 --- a/drivers/watchdog/Makefile
22 +++ b/drivers/watchdog/Makefile
23 @@ -49,6 +49,7 @@ obj-$(CONFIG_977_WATCHDOG) += wdt977.o
24 obj-$(CONFIG_GEMINI_WATCHDOG) += gemini_wdt.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
31 --- /dev/null
32 +++ b/drivers/watchdog/mpcore_wdt.c
33 @@ -0,0 +1,118 @@
34 +/*
35 + * Watchdog driver for ARM MPcore
36 + *
37 + * Copyright (C) 2017 Felix Fietkau <nbd@nbd.name>
38 + */
39 +
40 +#include <linux/export.h>
41 +#include <linux/module.h>
42 +#include <linux/kernel.h>
43 +#include <linux/watchdog.h>
44 +#include <linux/platform_device.h>
45 +#include <linux/io.h>
46 +#include <asm/smp_twd.h>
47 +
48 +static void __iomem *wdt_base;
49 +static int wdt_timeout = 60;
50 +
51 +static int mpcore_wdt_keepalive(struct watchdog_device *wdd)
52 +{
53 + static int perturb;
54 + u32 count;
55 +
56 + count = (twd_timer_get_rate() / 256) * wdt_timeout;
57 +
58 + /* Reload register needs a different value on each refresh */
59 + count += perturb;
60 + perturb = !perturb;
61 +
62 + iowrite32(count, wdt_base + TWD_WDOG_LOAD);
63 +
64 + return 0;
65 +}
66 +
67 +static int mpcore_wdt_start(struct watchdog_device *wdd)
68 +{
69 + mpcore_wdt_keepalive(wdd);
70 +
71 + /* prescale = 256, mode = 1, enable = 1 */
72 + iowrite32(0x0000FF09, wdt_base + TWD_WDOG_CONTROL);
73 +
74 + return 0;
75 +}
76 +
77 +static int mpcore_wdt_stop(struct watchdog_device *wdd)
78 +{
79 + iowrite32(0x12345678, wdt_base + TWD_WDOG_DISABLE);
80 + iowrite32(0x87654321, wdt_base + TWD_WDOG_DISABLE);
81 + iowrite32(0x0, wdt_base + TWD_WDOG_CONTROL);
82 +
83 + return 0;
84 +}
85 +
86 +static int mpcore_wdt_set_timeout(struct watchdog_device *wdd,
87 + unsigned int timeout)
88 +{
89 + mpcore_wdt_stop(wdd);
90 + wdt_timeout = timeout;
91 + mpcore_wdt_start(wdd);
92 +
93 + return 0;
94 +}
95 +
96 +static const struct watchdog_info mpcore_wdt_info = {
97 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
98 + .identity = "MPcore Watchdog",
99 +};
100 +
101 +static const struct watchdog_ops mpcore_wdt_ops = {
102 + .owner = THIS_MODULE,
103 + .start = mpcore_wdt_start,
104 + .stop = mpcore_wdt_stop,
105 + .ping = mpcore_wdt_keepalive,
106 + .set_timeout = mpcore_wdt_set_timeout,
107 +};
108 +
109 +static struct watchdog_device mpcore_wdt = {
110 + .info = &mpcore_wdt_info,
111 + .ops = &mpcore_wdt_ops,
112 + .min_timeout = 1,
113 + .max_timeout = 65535,
114 +};
115 +
116 +static int mpcore_wdt_probe(struct platform_device *pdev)
117 +{
118 + struct resource *res;
119 + unsigned long rate = twd_timer_get_rate();
120 +
121 + pr_info("MPCore WD init. clockrate: %u prescaler: %u countrate: %u timeout: %us\n", rate, 256, rate / 256, wdt_timeout);
122 +
123 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
124 + if (!res)
125 + return -ENODEV;
126 +
127 + wdt_base = devm_ioremap_resource(&pdev->dev, res);
128 + if (IS_ERR(wdt_base))
129 + return PTR_ERR(wdt_base);
130 +
131 + watchdog_register_device(&mpcore_wdt);
132 + return 0;
133 +}
134 +
135 +static int mpcore_wdt_remove(struct platform_device *dev)
136 +{
137 + watchdog_unregister_device(&mpcore_wdt);
138 + return 0;
139 +}
140 +
141 +static struct platform_driver mpcore_wdt_driver = {
142 + .probe = mpcore_wdt_probe,
143 + .remove = mpcore_wdt_remove,
144 + .driver = {
145 + .name = "mpcore_wdt",
146 + },
147 +};
148 +
149 +module_platform_driver(mpcore_wdt_driver);
150 +MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
151 +MODULE_LICENSE("GPL");
152 --- a/arch/arm/include/asm/smp_twd.h
153 +++ b/arch/arm/include/asm/smp_twd.h
154 @@ -34,5 +34,6 @@ struct twd_local_timer name __initdata =
155 };
156
157 int twd_local_timer_register(struct twd_local_timer *);
158 +unsigned long twd_timer_get_rate(void);
159
160 #endif
161 --- a/arch/arm/kernel/smp_twd.c
162 +++ b/arch/arm/kernel/smp_twd.c
163 @@ -15,6 +15,7 @@
164 #include <linux/delay.h>
165 #include <linux/device.h>
166 #include <linux/err.h>
167 +#include <linux/export.h>
168 #include <linux/smp.h>
169 #include <linux/jiffies.h>
170 #include <linux/clockchips.h>
171 @@ -380,6 +381,14 @@ int __init twd_local_timer_register(stru
172 return twd_local_timer_common_register(NULL);
173 }
174
175 +/* Needed by mpcore_wdt */
176 +unsigned long twd_timer_get_rate(void)
177 +{
178 + return twd_timer_rate;
179 +}
180 +EXPORT_SYMBOL_GPL(twd_timer_get_rate);
181 +
182 +
183 #ifdef CONFIG_OF
184 static int __init twd_local_timer_of_register(struct device_node *np)
185 {