8707bf9b6c0592916c889d6d7052045db2f1e7cc
[librecmc/librecmc.git] / target / linux / cns3xxx / patches-4.9 / 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 @@ -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.
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 @@ -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
31 --- /dev/null
32 +++ b/drivers/watchdog/mpcore_wdt.c
33 @@ -0,0 +1,117 @@
34 +/*
35 + * Watchdog driver for ARM MPcore
36 + *
37 + * Copyright (C) 2017 Felix Fietkau <nbd@nbd.name>
38 + */
39 +
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>
46 +
47 +static void __iomem *wdt_base;
48 +static int wdt_timeout = 60;
49 +
50 +static int mpcore_wdt_keepalive(struct watchdog_device *wdd)
51 +{
52 +       static int perturb;
53 +       u32 count;
54 +
55 +       count = ioread32(wdt_base + TWD_WDOG_COUNTER);
56 +       count = (~0U - count) * HZ / 5;
57 +       count /= 256; /* prescale */
58 +       count *= wdt_timeout;
59 +
60 +       /* Reload register needs a different value on each refresh */
61 +       count += perturb;
62 +       perturb = !perturb;
63 +
64 +       iowrite32(count, wdt_base + TWD_WDOG_LOAD);
65 +
66 +       return 0;
67 +}
68 +
69 +static int mpcore_wdt_start(struct watchdog_device *wdd)
70 +{
71 +       mpcore_wdt_keepalive(wdd);
72 +
73 +       /* prescale = 256, mode = 1, enable = 1 */
74 +       iowrite32(0x0000FF09, wdt_base + TWD_WDOG_CONTROL);
75 +
76 +       return 0;
77 +}
78 +
79 +static int mpcore_wdt_stop(struct watchdog_device *wdd)
80 +{
81 +       iowrite32(0x12345678, wdt_base + TWD_WDOG_DISABLE);
82 +       iowrite32(0x87654321, wdt_base + TWD_WDOG_DISABLE);
83 +       iowrite32(0x0, wdt_base + TWD_WDOG_CONTROL);
84 +
85 +       return 0;
86 +}
87 +
88 +static int mpcore_wdt_set_timeout(struct watchdog_device *wdd,
89 +                                unsigned int timeout)
90 +{
91 +       mpcore_wdt_stop(wdd);
92 +       wdt_timeout = timeout;
93 +       mpcore_wdt_start(wdd);
94 +
95 +       return 0;
96 +}
97 +
98 +static const struct watchdog_info mpcore_wdt_info = {
99 +       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
100 +       .identity = "MPcore Watchdog",
101 +};
102 +
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,
109 +};
110 +
111 +static struct watchdog_device mpcore_wdt = {
112 +       .info = &mpcore_wdt_info,
113 +       .ops = &mpcore_wdt_ops,
114 +       .min_timeout = 1,
115 +       .max_timeout = 65535,
116 +};
117 +
118 +static int mpcore_wdt_probe(struct platform_device *pdev)
119 +{
120 +       struct resource *res;
121 +
122 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
123 +       if (!res)
124 +               return -ENODEV;
125 +
126 +       wdt_base = devm_ioremap_resource(&pdev->dev, res);
127 +       if (IS_ERR(wdt_base))
128 +               return PTR_ERR(wdt_base);
129 +
130 +       watchdog_register_device(&mpcore_wdt);
131 +       return 0;
132 +}
133 +
134 +static int mpcore_wdt_remove(struct platform_device *dev)
135 +{
136 +       watchdog_unregister_device(&mpcore_wdt);
137 +       return 0;
138 +}
139 +
140 +static struct platform_driver mpcore_wdt_driver = {
141 +       .probe          = mpcore_wdt_probe,
142 +       .remove         = mpcore_wdt_remove,
143 +       .driver         = {
144 +               .name   = "mpcore_wdt",
145 +       },
146 +};
147 +
148 +module_platform_driver(mpcore_wdt_driver);
149 +MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
150 +MODULE_LICENSE("GPL");