mm: add prototype for __add_to_page_cache_locked()
[linux-2.6-microblaze.git] / drivers / watchdog / sama5d4_wdt.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Driver for Atmel SAMA5D4 Watchdog Timer
4  *
5  * Copyright (C) 2015-2019 Microchip Technology Inc. and its subsidiaries
6  */
7
8 #include <linux/delay.h>
9 #include <linux/interrupt.h>
10 #include <linux/io.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_device.h>
15 #include <linux/of_irq.h>
16 #include <linux/platform_device.h>
17 #include <linux/reboot.h>
18 #include <linux/watchdog.h>
19
20 #include "at91sam9_wdt.h"
21
22 /* minimum and maximum watchdog timeout, in seconds */
23 #define MIN_WDT_TIMEOUT         1
24 #define MAX_WDT_TIMEOUT         16
25 #define WDT_DEFAULT_TIMEOUT     MAX_WDT_TIMEOUT
26
27 #define WDT_SEC2TICKS(s)        ((s) ? (((s) << 8) - 1) : 0)
28
29 struct sama5d4_wdt {
30         struct watchdog_device  wdd;
31         void __iomem            *reg_base;
32         u32                     mr;
33         u32                     ir;
34         unsigned long           last_ping;
35         bool                    need_irq;
36         bool                    sam9x60_support;
37 };
38
39 static int wdt_timeout;
40 static bool nowayout = WATCHDOG_NOWAYOUT;
41
42 module_param(wdt_timeout, int, 0);
43 MODULE_PARM_DESC(wdt_timeout,
44         "Watchdog timeout in seconds. (default = "
45         __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")");
46
47 module_param(nowayout, bool, 0);
48 MODULE_PARM_DESC(nowayout,
49         "Watchdog cannot be stopped once started (default="
50         __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
51
52 #define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS))
53
54 #define wdt_read(wdt, field) \
55         readl_relaxed((wdt)->reg_base + (field))
56
57 /* 4 slow clock periods is 4/32768 = 122.07µs*/
58 #define WDT_DELAY       usecs_to_jiffies(123)
59
60 static void wdt_write(struct sama5d4_wdt *wdt, u32 field, u32 val)
61 {
62         /*
63          * WDT_CR and WDT_MR must not be modified within three slow clock
64          * periods following a restart of the watchdog performed by a write
65          * access in WDT_CR.
66          */
67         while (time_before(jiffies, wdt->last_ping + WDT_DELAY))
68                 usleep_range(30, 125);
69         writel_relaxed(val, wdt->reg_base + field);
70         wdt->last_ping = jiffies;
71 }
72
73 static void wdt_write_nosleep(struct sama5d4_wdt *wdt, u32 field, u32 val)
74 {
75         if (time_before(jiffies, wdt->last_ping + WDT_DELAY))
76                 udelay(123);
77         writel_relaxed(val, wdt->reg_base + field);
78         wdt->last_ping = jiffies;
79 }
80
81 static int sama5d4_wdt_start(struct watchdog_device *wdd)
82 {
83         struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
84
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         }
91         wdt_write(wdt, AT91_WDT_MR, wdt->mr);
92
93         return 0;
94 }
95
96 static int sama5d4_wdt_stop(struct watchdog_device *wdd)
97 {
98         struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
99
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         }
106         wdt_write(wdt, AT91_WDT_MR, wdt->mr);
107
108         return 0;
109 }
110
111 static int sama5d4_wdt_ping(struct watchdog_device *wdd)
112 {
113         struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
114
115         wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
116
117         return 0;
118 }
119
120 static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
121                                  unsigned int timeout)
122 {
123         struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
124         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         }
133
134         wdt->mr &= ~AT91_WDT_WDV;
135         wdt->mr |= AT91_WDT_SET_WDV(value);
136
137         /*
138          * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When
139          * setting the WDDIS bit, and while it is set, the fields WDV and WDD
140          * must not be modified.
141          * If the watchdog is enabled, then the timeout can be updated. Else,
142          * wait that the user enables it.
143          */
144         if (wdt_enabled)
145                 wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
146
147         wdd->timeout = timeout;
148
149         return 0;
150 }
151
152 static const struct watchdog_info sama5d4_wdt_info = {
153         .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
154         .identity = "Atmel SAMA5D4 Watchdog",
155 };
156
157 static const struct watchdog_ops sama5d4_wdt_ops = {
158         .owner = THIS_MODULE,
159         .start = sama5d4_wdt_start,
160         .stop = sama5d4_wdt_stop,
161         .ping = sama5d4_wdt_ping,
162         .set_timeout = sama5d4_wdt_set_timeout,
163 };
164
165 static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id)
166 {
167         struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id);
168         u32 reg;
169
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) {
176                 pr_crit("Atmel Watchdog Software Reset\n");
177                 emergency_restart();
178                 pr_crit("Reboot didn't succeed\n");
179         }
180
181         return IRQ_HANDLED;
182 }
183
184 static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
185 {
186         const char *tmp;
187
188         if (wdt->sam9x60_support)
189                 wdt->mr = AT91_SAM9X60_WDDIS;
190         else
191                 wdt->mr = AT91_WDT_WDDIS;
192
193         if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
194             !strcmp(tmp, "software"))
195                 wdt->need_irq = true;
196
197         if (of_property_read_bool(np, "atmel,idle-halt"))
198                 wdt->mr |= AT91_WDT_WDIDLEHLT;
199
200         if (of_property_read_bool(np, "atmel,dbg-halt"))
201                 wdt->mr |= AT91_WDT_WDDBGHLT;
202
203         return 0;
204 }
205
206 static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
207 {
208         u32 reg, val;
209
210         val = WDT_SEC2TICKS(WDT_DEFAULT_TIMEOUT);
211         /*
212          * When booting and resuming, the bootloader may have changed the
213          * watchdog configuration.
214          * If the watchdog is already running, we can safely update it.
215          * Else, we have to disable it properly.
216          */
217         if (!wdt_enabled) {
218                 reg = wdt_read(wdt, AT91_WDT_MR);
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)))
224                         wdt_write_nosleep(wdt, AT91_WDT_MR,
225                                           reg | AT91_WDT_WDDIS);
226         }
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
248         return 0;
249 }
250
251 static int sama5d4_wdt_probe(struct platform_device *pdev)
252 {
253         struct device *dev = &pdev->dev;
254         struct watchdog_device *wdd;
255         struct sama5d4_wdt *wdt;
256         void __iomem *regs;
257         u32 irq = 0;
258         int ret;
259
260         wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
261         if (!wdt)
262                 return -ENOMEM;
263
264         wdd = &wdt->wdd;
265         wdd->timeout = WDT_DEFAULT_TIMEOUT;
266         wdd->info = &sama5d4_wdt_info;
267         wdd->ops = &sama5d4_wdt_ops;
268         wdd->min_timeout = MIN_WDT_TIMEOUT;
269         wdd->max_timeout = MAX_WDT_TIMEOUT;
270         wdt->last_ping = jiffies;
271         wdt->sam9x60_support = of_device_is_compatible(dev->of_node,
272                                                        "microchip,sam9x60-wdt");
273
274         watchdog_set_drvdata(wdd, wdt);
275
276         regs = devm_platform_ioremap_resource(pdev, 0);
277         if (IS_ERR(regs))
278                 return PTR_ERR(regs);
279
280         wdt->reg_base = regs;
281
282         ret = of_sama5d4_wdt_init(dev->of_node, wdt);
283         if (ret)
284                 return ret;
285
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,
296                                        IRQF_SHARED | IRQF_IRQPOLL |
297                                        IRQF_NO_SUSPEND, pdev->name, pdev);
298                 if (ret) {
299                         dev_err(dev, "cannot register interrupt handler\n");
300                         return ret;
301                 }
302         }
303
304         watchdog_init_timeout(wdd, wdt_timeout, dev);
305
306         ret = sama5d4_wdt_init(wdt);
307         if (ret)
308                 return ret;
309
310         watchdog_set_nowayout(wdd, nowayout);
311
312         watchdog_stop_on_unregister(wdd);
313         ret = devm_watchdog_register_device(dev, wdd);
314         if (ret)
315                 return ret;
316
317         platform_set_drvdata(pdev, wdt);
318
319         dev_info(dev, "initialized (timeout = %d sec, nowayout = %d)\n",
320                  wdd->timeout, nowayout);
321
322         return 0;
323 }
324
325 static const struct of_device_id sama5d4_wdt_of_match[] = {
326         {
327                 .compatible = "atmel,sama5d4-wdt",
328         },
329         {
330                 .compatible = "microchip,sam9x60-wdt",
331         },
332         { }
333 };
334 MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
335
336 #ifdef CONFIG_PM_SLEEP
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)
348 {
349         struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
350
351         /*
352          * FIXME: writing MR also pings the watchdog which may not be desired.
353          * This should only be done when the registers are lost on suspend but
354          * there is no way to get this information right now.
355          */
356         sama5d4_wdt_init(wdt);
357
358         if (watchdog_active(&wdt->wdd))
359                 sama5d4_wdt_start(&wdt->wdd);
360
361         return 0;
362 }
363 #endif
364
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 };
369
370 static struct platform_driver sama5d4_wdt_driver = {
371         .probe          = sama5d4_wdt_probe,
372         .driver         = {
373                 .name   = "sama5d4_wdt",
374                 .pm     = &sama5d4_wdt_pm_ops,
375                 .of_match_table = sama5d4_wdt_of_match,
376         }
377 };
378 module_platform_driver(sama5d4_wdt_driver);
379
380 MODULE_AUTHOR("Atmel Corporation");
381 MODULE_DESCRIPTION("Atmel SAMA5D4 Watchdog Timer driver");
382 MODULE_LICENSE("GPL v2");