diff options
author | Johannes Thumshirn <jthumshirn@suse.de> | 2018-07-16 03:25:10 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@linux-watchdog.org> | 2018-08-02 09:57:12 -0400 |
commit | 81ceed41d0c2b2c9300de7bc30c1451680257f52 (patch) | |
tree | c3a7d1dbd87a011c13cf41129b58e02117e31a77 | |
parent | 28e65edd73f963e7a0838bf3a62106be55dcb925 (diff) |
watchdog: add driver for the MEN 16z069 IP-Core
Add a driver for the MEN 16z069 Watchdog and Reset Controller IP-Core.
Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: Michael Moese <mmoese@suse.de>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 10 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/menz69_wdt.c | 170 |
4 files changed, 187 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 192d7f73fd01..0b1015de1462 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -9299,6 +9299,12 @@ F: drivers/leds/leds-menf21bmc.c | |||
9299 | F: drivers/hwmon/menf21bmc_hwmon.c | 9299 | F: drivers/hwmon/menf21bmc_hwmon.c |
9300 | F: Documentation/hwmon/menf21bmc | 9300 | F: Documentation/hwmon/menf21bmc |
9301 | 9301 | ||
9302 | MEN Z069 WATCHDOG DRIVER | ||
9303 | M: Johannes Thumshirn <jth@kernel.org> | ||
9304 | L: linux-watchdog@vger.kernel.org | ||
9305 | S: Maintained | ||
9306 | F: drivers/watchdog/menz069_wdt.c | ||
9307 | |||
9302 | MESON AO CEC DRIVER FOR AMLOGIC SOCS | 9308 | MESON AO CEC DRIVER FOR AMLOGIC SOCS |
9303 | M: Neil Armstrong <narmstrong@baylibre.com> | 9309 | M: Neil Armstrong <narmstrong@baylibre.com> |
9304 | L: linux-media@lists.freedesktop.org | 9310 | L: linux-media@lists.freedesktop.org |
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9af07fd92763..df55d65bbb1c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -161,6 +161,16 @@ config MENF21BMC_WATCHDOG | |||
161 | This driver can also be built as a module. If so the module | 161 | This driver can also be built as a module. If so the module |
162 | will be called menf21bmc_wdt. | 162 | will be called menf21bmc_wdt. |
163 | 163 | ||
164 | config MENZ069_WATCHDOG | ||
165 | tristate "MEN 16Z069 Watchdog" | ||
166 | depends on MCB || COMPILE_TEST | ||
167 | select WATCHDOG_CORE | ||
168 | help | ||
169 | Say Y here to include support for the MEN 16Z069 Watchdog. | ||
170 | |||
171 | This driver can also be built as a module. If so the module | ||
172 | will be called menz069_wdt. | ||
173 | |||
164 | config TANGOX_WATCHDOG | 174 | config TANGOX_WATCHDOG |
165 | tristate "Sigma Designs SMP86xx/SMP87xx watchdog" | 175 | tristate "Sigma Designs SMP86xx/SMP87xx watchdog" |
166 | select WATCHDOG_CORE | 176 | select WATCHDOG_CORE |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 1d3c6b094fe5..bf92e7bf9ce0 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -215,4 +215,5 @@ obj-$(CONFIG_MAX77620_WATCHDOG) += max77620_wdt.o | |||
215 | obj-$(CONFIG_ZIIRAVE_WATCHDOG) += ziirave_wdt.o | 215 | obj-$(CONFIG_ZIIRAVE_WATCHDOG) += ziirave_wdt.o |
216 | obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o | 216 | obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o |
217 | obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o | 217 | obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o |
218 | obj-$(CONFIG_MENZ069_WATCHDOG) += menz69_wdt.o | ||
218 | obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o | 219 | obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o |
diff --git a/drivers/watchdog/menz69_wdt.c b/drivers/watchdog/menz69_wdt.c new file mode 100644 index 000000000000..ed18238c5407 --- /dev/null +++ b/drivers/watchdog/menz69_wdt.c | |||
@@ -0,0 +1,170 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Watchdog driver for the MEN z069 IP-Core | ||
4 | * | ||
5 | * Copyright (C) 2018 Johannes Thumshirn <jth@kernel.org> | ||
6 | */ | ||
7 | #include <linux/io.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/mcb.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/watchdog.h> | ||
12 | |||
13 | struct men_z069_drv { | ||
14 | struct watchdog_device wdt; | ||
15 | void __iomem *base; | ||
16 | struct resource *mem; | ||
17 | }; | ||
18 | |||
19 | #define MEN_Z069_WTR 0x10 | ||
20 | #define MEN_Z069_WTR_WDEN BIT(15) | ||
21 | #define MEN_Z069_WTR_WDET_MASK 0x7fff | ||
22 | #define MEN_Z069_WVR 0x14 | ||
23 | |||
24 | #define MEN_Z069_TIMER_FREQ 500 /* 500 Hz */ | ||
25 | #define MEN_Z069_WDT_COUNTER_MIN 1 | ||
26 | #define MEN_Z069_WDT_COUNTER_MAX 0x7fff | ||
27 | #define MEN_Z069_DEFAULT_TIMEOUT 30 | ||
28 | |||
29 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
30 | module_param(nowayout, bool, 0); | ||
31 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | ||
32 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
33 | |||
34 | static int men_z069_wdt_start(struct watchdog_device *wdt) | ||
35 | { | ||
36 | struct men_z069_drv *drv = watchdog_get_drvdata(wdt); | ||
37 | u16 val; | ||
38 | |||
39 | val = readw(drv->base + MEN_Z069_WTR); | ||
40 | val |= MEN_Z069_WTR_WDEN; | ||
41 | writew(val, drv->base + MEN_Z069_WTR); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int men_z069_wdt_stop(struct watchdog_device *wdt) | ||
47 | { | ||
48 | struct men_z069_drv *drv = watchdog_get_drvdata(wdt); | ||
49 | u16 val; | ||
50 | |||
51 | val = readw(drv->base + MEN_Z069_WTR); | ||
52 | val &= ~MEN_Z069_WTR_WDEN; | ||
53 | writew(val, drv->base + MEN_Z069_WTR); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int men_z069_wdt_ping(struct watchdog_device *wdt) | ||
59 | { | ||
60 | struct men_z069_drv *drv = watchdog_get_drvdata(wdt); | ||
61 | u16 val; | ||
62 | |||
63 | /* The watchdog trigger value toggles between 0x5555 and 0xaaaa */ | ||
64 | val = readw(drv->base + MEN_Z069_WVR); | ||
65 | val ^= 0xffff; | ||
66 | writew(val, drv->base + MEN_Z069_WVR); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int men_z069_wdt_set_timeout(struct watchdog_device *wdt, | ||
72 | unsigned int timeout) | ||
73 | { | ||
74 | struct men_z069_drv *drv = watchdog_get_drvdata(wdt); | ||
75 | u16 reg, val, ena; | ||
76 | |||
77 | wdt->timeout = timeout; | ||
78 | val = timeout * MEN_Z069_TIMER_FREQ; | ||
79 | |||
80 | reg = readw(drv->base + MEN_Z069_WVR); | ||
81 | ena = reg & MEN_Z069_WTR_WDEN; | ||
82 | reg = ena | val; | ||
83 | writew(reg, drv->base + MEN_Z069_WTR); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static const struct watchdog_info men_z069_info = { | ||
89 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | ||
90 | .identity = "MEN z069 Watchdog", | ||
91 | }; | ||
92 | |||
93 | static const struct watchdog_ops men_z069_ops = { | ||
94 | .owner = THIS_MODULE, | ||
95 | .start = men_z069_wdt_start, | ||
96 | .stop = men_z069_wdt_stop, | ||
97 | .ping = men_z069_wdt_ping, | ||
98 | .set_timeout = men_z069_wdt_set_timeout, | ||
99 | }; | ||
100 | |||
101 | static struct watchdog_device men_z069_wdt = { | ||
102 | .info = &men_z069_info, | ||
103 | .ops = &men_z069_ops, | ||
104 | .timeout = MEN_Z069_DEFAULT_TIMEOUT, | ||
105 | .min_timeout = 1, | ||
106 | .max_timeout = MEN_Z069_WDT_COUNTER_MAX / MEN_Z069_TIMER_FREQ, | ||
107 | }; | ||
108 | |||
109 | static int men_z069_probe(struct mcb_device *dev, | ||
110 | const struct mcb_device_id *id) | ||
111 | { | ||
112 | struct men_z069_drv *drv; | ||
113 | struct resource *mem; | ||
114 | |||
115 | drv = devm_kzalloc(&dev->dev, sizeof(struct men_z069_drv), GFP_KERNEL); | ||
116 | if (!drv) | ||
117 | return -ENOMEM; | ||
118 | |||
119 | mem = mcb_request_mem(dev, "z069-wdt"); | ||
120 | if (IS_ERR(mem)) | ||
121 | return PTR_ERR(mem); | ||
122 | |||
123 | drv->base = devm_ioremap(&dev->dev, mem->start, resource_size(mem)); | ||
124 | if (drv->base == NULL) | ||
125 | goto release_mem; | ||
126 | |||
127 | drv->mem = mem; | ||
128 | |||
129 | drv->wdt = men_z069_wdt; | ||
130 | watchdog_init_timeout(&drv->wdt, 0, &dev->dev); | ||
131 | watchdog_set_nowayout(&drv->wdt, nowayout); | ||
132 | watchdog_set_drvdata(&drv->wdt, drv); | ||
133 | drv->wdt.parent = &dev->dev; | ||
134 | mcb_set_drvdata(dev, drv); | ||
135 | |||
136 | return watchdog_register_device(&men_z069_wdt); | ||
137 | |||
138 | release_mem: | ||
139 | mcb_release_mem(mem); | ||
140 | return -ENOMEM; | ||
141 | } | ||
142 | |||
143 | static void men_z069_remove(struct mcb_device *dev) | ||
144 | { | ||
145 | struct men_z069_drv *drv = mcb_get_drvdata(dev); | ||
146 | |||
147 | watchdog_unregister_device(&drv->wdt); | ||
148 | mcb_release_mem(drv->mem); | ||
149 | } | ||
150 | |||
151 | static const struct mcb_device_id men_z069_ids[] = { | ||
152 | { .device = 0x45 }, | ||
153 | { } | ||
154 | }; | ||
155 | MODULE_DEVICE_TABLE(mcb, men_z069_ids); | ||
156 | |||
157 | static struct mcb_driver men_z069_driver = { | ||
158 | .driver = { | ||
159 | .name = "z069-wdt", | ||
160 | .owner = THIS_MODULE, | ||
161 | }, | ||
162 | .probe = men_z069_probe, | ||
163 | .remove = men_z069_remove, | ||
164 | .id_table = men_z069_ids, | ||
165 | }; | ||
166 | module_mcb_driver(men_z069_driver); | ||
167 | |||
168 | MODULE_AUTHOR("Johannes Thumshirn <jth@kernel.org>"); | ||
169 | MODULE_LICENSE("GPL v2"); | ||
170 | MODULE_ALIAS("mcb:16z069"); | ||