hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/watchdog/sama5d4_wdt.c
....@@ -1,9 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Driver for Atmel SAMA5D4 Watchdog Timer
34 *
4
- * Copyright (C) 2015 Atmel Corporation
5
- *
6
- * Licensed under GPLv2.
5
+ * Copyright (C) 2015-2019 Microchip Technology Inc. and its subsidiaries
76 */
87
98 #include <linux/delay.h>
....@@ -12,6 +11,7 @@
1211 #include <linux/kernel.h>
1312 #include <linux/module.h>
1413 #include <linux/of.h>
14
+#include <linux/of_device.h>
1515 #include <linux/of_irq.h>
1616 #include <linux/platform_device.h>
1717 #include <linux/reboot.h>
....@@ -30,7 +30,10 @@
3030 struct watchdog_device wdd;
3131 void __iomem *reg_base;
3232 u32 mr;
33
+ u32 ir;
3334 unsigned long last_ping;
35
+ bool need_irq;
36
+ bool sam9x60_support;
3437 };
3538
3639 static int wdt_timeout;
....@@ -79,7 +82,12 @@
7982 {
8083 struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
8184
82
- wdt->mr &= ~AT91_WDT_WDDIS;
85
+ if (wdt->sam9x60_support) {
86
+ writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IER);
87
+ wdt->mr &= ~AT91_SAM9X60_WDDIS;
88
+ } else {
89
+ wdt->mr &= ~AT91_WDT_WDDIS;
90
+ }
8391 wdt_write(wdt, AT91_WDT_MR, wdt->mr);
8492
8593 return 0;
....@@ -89,7 +97,12 @@
8997 {
9098 struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
9199
92
- wdt->mr |= AT91_WDT_WDDIS;
100
+ if (wdt->sam9x60_support) {
101
+ writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IDR);
102
+ wdt->mr |= AT91_SAM9X60_WDDIS;
103
+ } else {
104
+ wdt->mr |= AT91_WDT_WDDIS;
105
+ }
93106 wdt_write(wdt, AT91_WDT_MR, wdt->mr);
94107
95108 return 0;
....@@ -109,6 +122,14 @@
109122 {
110123 struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
111124 u32 value = WDT_SEC2TICKS(timeout);
125
+
126
+ if (wdt->sam9x60_support) {
127
+ wdt_write(wdt, AT91_SAM9X60_WLR,
128
+ AT91_SAM9X60_SET_COUNTER(value));
129
+
130
+ wdd->timeout = timeout;
131
+ return 0;
132
+ }
112133
113134 wdt->mr &= ~AT91_WDT_WDV;
114135 wdt->mr |= AT91_WDT_SET_WDV(value);
....@@ -144,8 +165,14 @@
144165 static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id)
145166 {
146167 struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id);
168
+ u32 reg;
147169
148
- if (wdt_read(wdt, AT91_WDT_SR)) {
170
+ if (wdt->sam9x60_support)
171
+ reg = wdt_read(wdt, AT91_SAM9X60_ISR);
172
+ else
173
+ reg = wdt_read(wdt, AT91_WDT_SR);
174
+
175
+ if (reg) {
149176 pr_crit("Atmel Watchdog Software Reset\n");
150177 emergency_restart();
151178 pr_crit("Reboot didn't succeed\n");
....@@ -158,13 +185,14 @@
158185 {
159186 const char *tmp;
160187
161
- wdt->mr = AT91_WDT_WDDIS;
188
+ if (wdt->sam9x60_support)
189
+ wdt->mr = AT91_SAM9X60_WDDIS;
190
+ else
191
+ wdt->mr = AT91_WDT_WDDIS;
162192
163193 if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
164194 !strcmp(tmp, "software"))
165
- wdt->mr |= AT91_WDT_WDFIEN;
166
- else
167
- wdt->mr |= AT91_WDT_WDRSTEN;
195
+ wdt->need_irq = true;
168196
169197 if (of_property_read_bool(np, "atmel,idle-halt"))
170198 wdt->mr |= AT91_WDT_WDIDLEHLT;
....@@ -177,35 +205,59 @@
177205
178206 static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
179207 {
180
- u32 reg;
208
+ u32 reg, val;
209
+
210
+ val = WDT_SEC2TICKS(WDT_DEFAULT_TIMEOUT);
181211 /*
182212 * When booting and resuming, the bootloader may have changed the
183213 * watchdog configuration.
184214 * If the watchdog is already running, we can safely update it.
185215 * Else, we have to disable it properly.
186216 */
187
- if (wdt_enabled) {
188
- wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
189
- } else {
217
+ if (!wdt_enabled) {
190218 reg = wdt_read(wdt, AT91_WDT_MR);
191
- if (!(reg & AT91_WDT_WDDIS))
219
+ if (wdt->sam9x60_support && (!(reg & AT91_SAM9X60_WDDIS)))
220
+ wdt_write_nosleep(wdt, AT91_WDT_MR,
221
+ reg | AT91_SAM9X60_WDDIS);
222
+ else if (!wdt->sam9x60_support &&
223
+ (!(reg & AT91_WDT_WDDIS)))
192224 wdt_write_nosleep(wdt, AT91_WDT_MR,
193225 reg | AT91_WDT_WDDIS);
194226 }
227
+
228
+ if (wdt->sam9x60_support) {
229
+ if (wdt->need_irq)
230
+ wdt->ir = AT91_SAM9X60_PERINT;
231
+ else
232
+ wdt->mr |= AT91_SAM9X60_PERIODRST;
233
+
234
+ wdt_write(wdt, AT91_SAM9X60_IER, wdt->ir);
235
+ wdt_write(wdt, AT91_SAM9X60_WLR, AT91_SAM9X60_SET_COUNTER(val));
236
+ } else {
237
+ wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
238
+ wdt->mr |= AT91_WDT_SET_WDV(val);
239
+
240
+ if (wdt->need_irq)
241
+ wdt->mr |= AT91_WDT_WDFIEN;
242
+ else
243
+ wdt->mr |= AT91_WDT_WDRSTEN;
244
+ }
245
+
246
+ wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
247
+
195248 return 0;
196249 }
197250
198251 static int sama5d4_wdt_probe(struct platform_device *pdev)
199252 {
253
+ struct device *dev = &pdev->dev;
200254 struct watchdog_device *wdd;
201255 struct sama5d4_wdt *wdt;
202
- struct resource *res;
203256 void __iomem *regs;
204257 u32 irq = 0;
205
- u32 timeout;
206258 int ret;
207259
208
- wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
260
+ wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
209261 if (!wdt)
210262 return -ENOMEM;
211263
....@@ -216,41 +268,40 @@
216268 wdd->min_timeout = MIN_WDT_TIMEOUT;
217269 wdd->max_timeout = MAX_WDT_TIMEOUT;
218270 wdt->last_ping = jiffies;
271
+ wdt->sam9x60_support = of_device_is_compatible(dev->of_node,
272
+ "microchip,sam9x60-wdt");
219273
220274 watchdog_set_drvdata(wdd, wdt);
221275
222
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
223
- regs = devm_ioremap_resource(&pdev->dev, res);
276
+ regs = devm_platform_ioremap_resource(pdev, 0);
224277 if (IS_ERR(regs))
225278 return PTR_ERR(regs);
226279
227280 wdt->reg_base = regs;
228281
229
- irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
230
- if (!irq)
231
- dev_warn(&pdev->dev, "failed to get IRQ from DT\n");
232
-
233
- ret = of_sama5d4_wdt_init(pdev->dev.of_node, wdt);
282
+ ret = of_sama5d4_wdt_init(dev->of_node, wdt);
234283 if (ret)
235284 return ret;
236285
237
- if ((wdt->mr & AT91_WDT_WDFIEN) && irq) {
238
- ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler,
286
+ if (wdt->need_irq) {
287
+ irq = irq_of_parse_and_map(dev->of_node, 0);
288
+ if (!irq) {
289
+ dev_warn(dev, "failed to get IRQ from DT\n");
290
+ wdt->need_irq = false;
291
+ }
292
+ }
293
+
294
+ if (wdt->need_irq) {
295
+ ret = devm_request_irq(dev, irq, sama5d4_wdt_irq_handler,
239296 IRQF_SHARED | IRQF_IRQPOLL |
240297 IRQF_NO_SUSPEND, pdev->name, pdev);
241298 if (ret) {
242
- dev_err(&pdev->dev,
243
- "cannot register interrupt handler\n");
299
+ dev_err(dev, "cannot register interrupt handler\n");
244300 return ret;
245301 }
246302 }
247303
248
- watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev);
249
-
250
- timeout = WDT_SEC2TICKS(wdd->timeout);
251
-
252
- wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
253
- wdt->mr |= AT91_WDT_SET_WDV(timeout);
304
+ watchdog_init_timeout(wdd, wdt_timeout, dev);
254305
255306 ret = sama5d4_wdt_init(wdt);
256307 if (ret)
....@@ -258,39 +309,42 @@
258309
259310 watchdog_set_nowayout(wdd, nowayout);
260311
261
- ret = watchdog_register_device(wdd);
262
- if (ret) {
263
- dev_err(&pdev->dev, "failed to register watchdog device\n");
312
+ watchdog_stop_on_unregister(wdd);
313
+ ret = devm_watchdog_register_device(dev, wdd);
314
+ if (ret)
264315 return ret;
265
- }
266316
267317 platform_set_drvdata(pdev, wdt);
268318
269
- dev_info(&pdev->dev, "initialized (timeout = %d sec, nowayout = %d)\n",
319
+ dev_info(dev, "initialized (timeout = %d sec, nowayout = %d)\n",
270320 wdd->timeout, nowayout);
271321
272322 return 0;
273323 }
274324
275
-static int sama5d4_wdt_remove(struct platform_device *pdev)
276
-{
277
- struct sama5d4_wdt *wdt = platform_get_drvdata(pdev);
278
-
279
- sama5d4_wdt_stop(&wdt->wdd);
280
-
281
- watchdog_unregister_device(&wdt->wdd);
282
-
283
- return 0;
284
-}
285
-
286325 static const struct of_device_id sama5d4_wdt_of_match[] = {
287
- { .compatible = "atmel,sama5d4-wdt", },
326
+ {
327
+ .compatible = "atmel,sama5d4-wdt",
328
+ },
329
+ {
330
+ .compatible = "microchip,sam9x60-wdt",
331
+ },
288332 { }
289333 };
290334 MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
291335
292336 #ifdef CONFIG_PM_SLEEP
293
-static int sama5d4_wdt_resume(struct device *dev)
337
+static int sama5d4_wdt_suspend_late(struct device *dev)
338
+{
339
+ struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
340
+
341
+ if (watchdog_active(&wdt->wdd))
342
+ sama5d4_wdt_stop(&wdt->wdd);
343
+
344
+ return 0;
345
+}
346
+
347
+static int sama5d4_wdt_resume_early(struct device *dev)
294348 {
295349 struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
296350
....@@ -301,16 +355,20 @@
301355 */
302356 sama5d4_wdt_init(wdt);
303357
358
+ if (watchdog_active(&wdt->wdd))
359
+ sama5d4_wdt_start(&wdt->wdd);
360
+
304361 return 0;
305362 }
306363 #endif
307364
308
-static SIMPLE_DEV_PM_OPS(sama5d4_wdt_pm_ops, NULL,
309
- sama5d4_wdt_resume);
365
+static const struct dev_pm_ops sama5d4_wdt_pm_ops = {
366
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late,
367
+ sama5d4_wdt_resume_early)
368
+};
310369
311370 static struct platform_driver sama5d4_wdt_driver = {
312371 .probe = sama5d4_wdt_probe,
313
- .remove = sama5d4_wdt_remove,
314372 .driver = {
315373 .name = "sama5d4_wdt",
316374 .pm = &sama5d4_wdt_pm_ops,