Merge tag 'drm-misc-fixes-2022-07-21' of git://anongit.freedesktop.org/drm/drm-misc...
[linux-2.6-microblaze.git] / drivers / watchdog / s3c2410_wdt.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2004 Simtec Electronics
4  *      Ben Dooks <ben@simtec.co.uk>
5  *
6  * S3C2410 Watchdog Timer Support
7  *
8  * Based on, softdog.c by Alan Cox,
9  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
10  */
11
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/types.h>
15 #include <linux/timer.h>
16 #include <linux/watchdog.h>
17 #include <linux/platform_device.h>
18 #include <linux/interrupt.h>
19 #include <linux/clk.h>
20 #include <linux/uaccess.h>
21 #include <linux/io.h>
22 #include <linux/cpufreq.h>
23 #include <linux/slab.h>
24 #include <linux/err.h>
25 #include <linux/of.h>
26 #include <linux/of_device.h>
27 #include <linux/mfd/syscon.h>
28 #include <linux/regmap.h>
29 #include <linux/delay.h>
30
31 #define S3C2410_WTCON           0x00
32 #define S3C2410_WTDAT           0x04
33 #define S3C2410_WTCNT           0x08
34 #define S3C2410_WTCLRINT        0x0c
35
36 #define S3C2410_WTCNT_MAXCNT    0xffff
37
38 #define S3C2410_WTCON_RSTEN     (1 << 0)
39 #define S3C2410_WTCON_INTEN     (1 << 2)
40 #define S3C2410_WTCON_ENABLE    (1 << 5)
41
42 #define S3C2410_WTCON_DIV16     (0 << 3)
43 #define S3C2410_WTCON_DIV32     (1 << 3)
44 #define S3C2410_WTCON_DIV64     (2 << 3)
45 #define S3C2410_WTCON_DIV128    (3 << 3)
46
47 #define S3C2410_WTCON_MAXDIV    0x80
48
49 #define S3C2410_WTCON_PRESCALE(x)       ((x) << 8)
50 #define S3C2410_WTCON_PRESCALE_MASK     (0xff << 8)
51 #define S3C2410_WTCON_PRESCALE_MAX      0xff
52
53 #define S3C2410_WATCHDOG_ATBOOT         (0)
54 #define S3C2410_WATCHDOG_DEFAULT_TIME   (15)
55
56 #define EXYNOS5_RST_STAT_REG_OFFSET             0x0404
57 #define EXYNOS5_WDT_DISABLE_REG_OFFSET          0x0408
58 #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET       0x040c
59 #define EXYNOS850_CLUSTER0_NONCPU_OUT           0x1220
60 #define EXYNOS850_CLUSTER0_NONCPU_INT_EN        0x1244
61 #define EXYNOS850_CLUSTER1_NONCPU_OUT           0x1620
62 #define EXYNOS850_CLUSTER1_NONCPU_INT_EN        0x1644
63
64 #define EXYNOS850_CLUSTER0_WDTRESET_BIT         24
65 #define EXYNOS850_CLUSTER1_WDTRESET_BIT         23
66
67 /**
68  * DOC: Quirk flags for different Samsung watchdog IP-cores
69  *
70  * This driver supports multiple Samsung SoCs, each of which might have
71  * different set of registers and features supported. As watchdog block
72  * sometimes requires modifying PMU registers for proper functioning, register
73  * differences in both watchdog and PMU IP-cores should be accounted for. Quirk
74  * flags described below serve the purpose of telling the driver about mentioned
75  * SoC traits, and can be specified in driver data for each particular supported
76  * device.
77  *
78  * %QUIRK_HAS_WTCLRINT_REG: Watchdog block has WTCLRINT register. It's used to
79  * clear the interrupt once the interrupt service routine is complete. It's
80  * write-only, writing any values to this register clears the interrupt, but
81  * reading is not permitted.
82  *
83  * %QUIRK_HAS_PMU_MASK_RESET: PMU block has the register for disabling/enabling
84  * WDT reset request. On old SoCs it's usually called MASK_WDT_RESET_REQUEST,
85  * new SoCs have CLUSTERx_NONCPU_INT_EN register, which 'mask_bit' value is
86  * inverted compared to the former one.
87  *
88  * %QUIRK_HAS_PMU_RST_STAT: PMU block has RST_STAT (reset status) register,
89  * which contains bits indicating the reason for most recent CPU reset. If
90  * present, driver will use this register to check if previous reboot was due to
91  * watchdog timer reset.
92  *
93  * %QUIRK_HAS_PMU_AUTO_DISABLE: PMU block has AUTOMATIC_WDT_RESET_DISABLE
94  * register. If 'mask_bit' bit is set, PMU will disable WDT reset when
95  * corresponding processor is in reset state.
96  *
97  * %QUIRK_HAS_PMU_CNT_EN: PMU block has some register (e.g. CLUSTERx_NONCPU_OUT)
98  * with "watchdog counter enable" bit. That bit should be set to make watchdog
99  * counter running.
100  */
101 #define QUIRK_HAS_WTCLRINT_REG                  (1 << 0)
102 #define QUIRK_HAS_PMU_MASK_RESET                (1 << 1)
103 #define QUIRK_HAS_PMU_RST_STAT                  (1 << 2)
104 #define QUIRK_HAS_PMU_AUTO_DISABLE              (1 << 3)
105 #define QUIRK_HAS_PMU_CNT_EN                    (1 << 4)
106
107 /* These quirks require that we have a PMU register map */
108 #define QUIRKS_HAVE_PMUREG \
109         (QUIRK_HAS_PMU_MASK_RESET | QUIRK_HAS_PMU_RST_STAT | \
110          QUIRK_HAS_PMU_AUTO_DISABLE | QUIRK_HAS_PMU_CNT_EN)
111
112 static bool nowayout    = WATCHDOG_NOWAYOUT;
113 static int tmr_margin;
114 static int tmr_atboot   = S3C2410_WATCHDOG_ATBOOT;
115 static int soft_noboot;
116
117 module_param(tmr_margin,  int, 0);
118 module_param(tmr_atboot,  int, 0);
119 module_param(nowayout,   bool, 0);
120 module_param(soft_noboot, int, 0);
121
122 MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default="
123                 __MODULE_STRING(S3C2410_WATCHDOG_DEFAULT_TIME) ")");
124 MODULE_PARM_DESC(tmr_atboot,
125                 "Watchdog is started at boot time if set to 1, default="
126                         __MODULE_STRING(S3C2410_WATCHDOG_ATBOOT));
127 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
128                         __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
129 MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default 0)");
130
131 /**
132  * struct s3c2410_wdt_variant - Per-variant config data
133  *
134  * @disable_reg: Offset in pmureg for the register that disables the watchdog
135  * timer reset functionality.
136  * @mask_reset_reg: Offset in pmureg for the register that masks the watchdog
137  * timer reset functionality.
138  * @mask_reset_inv: If set, mask_reset_reg value will have inverted meaning.
139  * @mask_bit: Bit number for the watchdog timer in the disable register and the
140  * mask reset register.
141  * @rst_stat_reg: Offset in pmureg for the register that has the reset status.
142  * @rst_stat_bit: Bit number in the rst_stat register indicating a watchdog
143  * reset.
144  * @cnt_en_reg: Offset in pmureg for the register that enables WDT counter.
145  * @cnt_en_bit: Bit number for "watchdog counter enable" in cnt_en register.
146  * @quirks: A bitfield of quirks.
147  */
148
149 struct s3c2410_wdt_variant {
150         int disable_reg;
151         int mask_reset_reg;
152         bool mask_reset_inv;
153         int mask_bit;
154         int rst_stat_reg;
155         int rst_stat_bit;
156         int cnt_en_reg;
157         int cnt_en_bit;
158         u32 quirks;
159 };
160
161 struct s3c2410_wdt {
162         struct device           *dev;
163         struct clk              *bus_clk; /* for register interface (PCLK) */
164         struct clk              *src_clk; /* for WDT counter */
165         void __iomem            *reg_base;
166         unsigned int            count;
167         spinlock_t              lock;
168         unsigned long           wtcon_save;
169         unsigned long           wtdat_save;
170         struct watchdog_device  wdt_device;
171         struct notifier_block   freq_transition;
172         const struct s3c2410_wdt_variant *drv_data;
173         struct regmap *pmureg;
174 };
175
176 static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
177         .quirks = 0
178 };
179
180 #ifdef CONFIG_OF
181 static const struct s3c2410_wdt_variant drv_data_s3c6410 = {
182         .quirks = QUIRK_HAS_WTCLRINT_REG,
183 };
184
185 static const struct s3c2410_wdt_variant drv_data_exynos5250  = {
186         .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
187         .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
188         .mask_bit = 20,
189         .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
190         .rst_stat_bit = 20,
191         .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \
192                   QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_AUTO_DISABLE,
193 };
194
195 static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
196         .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
197         .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
198         .mask_bit = 0,
199         .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
200         .rst_stat_bit = 9,
201         .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \
202                   QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_AUTO_DISABLE,
203 };
204
205 static const struct s3c2410_wdt_variant drv_data_exynos7 = {
206         .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
207         .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
208         .mask_bit = 23,
209         .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
210         .rst_stat_bit = 23,     /* A57 WDTRESET */
211         .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \
212                   QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_AUTO_DISABLE,
213 };
214
215 static const struct s3c2410_wdt_variant drv_data_exynos850_cl0 = {
216         .mask_reset_reg = EXYNOS850_CLUSTER0_NONCPU_INT_EN,
217         .mask_bit = 2,
218         .mask_reset_inv = true,
219         .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
220         .rst_stat_bit = EXYNOS850_CLUSTER0_WDTRESET_BIT,
221         .cnt_en_reg = EXYNOS850_CLUSTER0_NONCPU_OUT,
222         .cnt_en_bit = 7,
223         .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \
224                   QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN,
225 };
226
227 static const struct s3c2410_wdt_variant drv_data_exynos850_cl1 = {
228         .mask_reset_reg = EXYNOS850_CLUSTER1_NONCPU_INT_EN,
229         .mask_bit = 2,
230         .mask_reset_inv = true,
231         .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
232         .rst_stat_bit = EXYNOS850_CLUSTER1_WDTRESET_BIT,
233         .cnt_en_reg = EXYNOS850_CLUSTER1_NONCPU_OUT,
234         .cnt_en_bit = 7,
235         .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \
236                   QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN,
237 };
238
239 static const struct of_device_id s3c2410_wdt_match[] = {
240         { .compatible = "samsung,s3c2410-wdt",
241           .data = &drv_data_s3c2410 },
242         { .compatible = "samsung,s3c6410-wdt",
243           .data = &drv_data_s3c6410 },
244         { .compatible = "samsung,exynos5250-wdt",
245           .data = &drv_data_exynos5250 },
246         { .compatible = "samsung,exynos5420-wdt",
247           .data = &drv_data_exynos5420 },
248         { .compatible = "samsung,exynos7-wdt",
249           .data = &drv_data_exynos7 },
250         { .compatible = "samsung,exynos850-wdt",
251           .data = &drv_data_exynos850_cl0 },
252         {},
253 };
254 MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
255 #endif
256
257 static const struct platform_device_id s3c2410_wdt_ids[] = {
258         {
259                 .name = "s3c2410-wdt",
260                 .driver_data = (unsigned long)&drv_data_s3c2410,
261         },
262         {}
263 };
264 MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids);
265
266 /* functions */
267
268 static inline unsigned long s3c2410wdt_get_freq(struct s3c2410_wdt *wdt)
269 {
270         return clk_get_rate(wdt->src_clk ? wdt->src_clk : wdt->bus_clk);
271 }
272
273 static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt)
274 {
275         const unsigned long freq = s3c2410wdt_get_freq(wdt);
276
277         return S3C2410_WTCNT_MAXCNT / (freq / (S3C2410_WTCON_PRESCALE_MAX + 1)
278                                        / S3C2410_WTCON_MAXDIV);
279 }
280
281 static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb)
282 {
283         return container_of(nb, struct s3c2410_wdt, freq_transition);
284 }
285
286 static int s3c2410wdt_disable_wdt_reset(struct s3c2410_wdt *wdt, bool mask)
287 {
288         const u32 mask_val = BIT(wdt->drv_data->mask_bit);
289         const u32 val = mask ? mask_val : 0;
290         int ret;
291
292         ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->disable_reg,
293                                  mask_val, val);
294         if (ret < 0)
295                 dev_err(wdt->dev, "failed to update reg(%d)\n", ret);
296
297         return ret;
298 }
299
300 static int s3c2410wdt_mask_wdt_reset(struct s3c2410_wdt *wdt, bool mask)
301 {
302         const u32 mask_val = BIT(wdt->drv_data->mask_bit);
303         const bool val_inv = wdt->drv_data->mask_reset_inv;
304         const u32 val = (mask ^ val_inv) ? mask_val : 0;
305         int ret;
306
307         ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->mask_reset_reg,
308                                  mask_val, val);
309         if (ret < 0)
310                 dev_err(wdt->dev, "failed to update reg(%d)\n", ret);
311
312         return ret;
313 }
314
315 static int s3c2410wdt_enable_counter(struct s3c2410_wdt *wdt, bool en)
316 {
317         const u32 mask_val = BIT(wdt->drv_data->cnt_en_bit);
318         const u32 val = en ? mask_val : 0;
319         int ret;
320
321         ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->cnt_en_reg,
322                                  mask_val, val);
323         if (ret < 0)
324                 dev_err(wdt->dev, "failed to update reg(%d)\n", ret);
325
326         return ret;
327 }
328
329 static int s3c2410wdt_enable(struct s3c2410_wdt *wdt, bool en)
330 {
331         int ret;
332
333         if (wdt->drv_data->quirks & QUIRK_HAS_PMU_AUTO_DISABLE) {
334                 ret = s3c2410wdt_disable_wdt_reset(wdt, !en);
335                 if (ret < 0)
336                         return ret;
337         }
338
339         if (wdt->drv_data->quirks & QUIRK_HAS_PMU_MASK_RESET) {
340                 ret = s3c2410wdt_mask_wdt_reset(wdt, !en);
341                 if (ret < 0)
342                         return ret;
343         }
344
345         if (wdt->drv_data->quirks & QUIRK_HAS_PMU_CNT_EN) {
346                 ret = s3c2410wdt_enable_counter(wdt, en);
347                 if (ret < 0)
348                         return ret;
349         }
350
351         return 0;
352 }
353
354 static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
355 {
356         struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
357
358         spin_lock(&wdt->lock);
359         writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
360         spin_unlock(&wdt->lock);
361
362         return 0;
363 }
364
365 static void __s3c2410wdt_stop(struct s3c2410_wdt *wdt)
366 {
367         unsigned long wtcon;
368
369         wtcon = readl(wdt->reg_base + S3C2410_WTCON);
370         wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
371         writel(wtcon, wdt->reg_base + S3C2410_WTCON);
372 }
373
374 static int s3c2410wdt_stop(struct watchdog_device *wdd)
375 {
376         struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
377
378         spin_lock(&wdt->lock);
379         __s3c2410wdt_stop(wdt);
380         spin_unlock(&wdt->lock);
381
382         return 0;
383 }
384
385 static int s3c2410wdt_start(struct watchdog_device *wdd)
386 {
387         unsigned long wtcon;
388         struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
389
390         spin_lock(&wdt->lock);
391
392         __s3c2410wdt_stop(wdt);
393
394         wtcon = readl(wdt->reg_base + S3C2410_WTCON);
395         wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
396
397         if (soft_noboot) {
398                 wtcon |= S3C2410_WTCON_INTEN;
399                 wtcon &= ~S3C2410_WTCON_RSTEN;
400         } else {
401                 wtcon &= ~S3C2410_WTCON_INTEN;
402                 wtcon |= S3C2410_WTCON_RSTEN;
403         }
404
405         dev_dbg(wdt->dev, "Starting watchdog: count=0x%08x, wtcon=%08lx\n",
406                 wdt->count, wtcon);
407
408         writel(wdt->count, wdt->reg_base + S3C2410_WTDAT);
409         writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
410         writel(wtcon, wdt->reg_base + S3C2410_WTCON);
411         spin_unlock(&wdt->lock);
412
413         return 0;
414 }
415
416 static inline int s3c2410wdt_is_running(struct s3c2410_wdt *wdt)
417 {
418         return readl(wdt->reg_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
419 }
420
421 static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd,
422                                     unsigned int timeout)
423 {
424         struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
425         unsigned long freq = s3c2410wdt_get_freq(wdt);
426         unsigned int count;
427         unsigned int divisor = 1;
428         unsigned long wtcon;
429
430         if (timeout < 1)
431                 return -EINVAL;
432
433         freq = DIV_ROUND_UP(freq, 128);
434         count = timeout * freq;
435
436         dev_dbg(wdt->dev, "Heartbeat: count=%d, timeout=%d, freq=%lu\n",
437                 count, timeout, freq);
438
439         /* if the count is bigger than the watchdog register,
440            then work out what we need to do (and if) we can
441            actually make this value
442         */
443
444         if (count >= 0x10000) {
445                 divisor = DIV_ROUND_UP(count, 0xffff);
446
447                 if (divisor > 0x100) {
448                         dev_err(wdt->dev, "timeout %d too big\n", timeout);
449                         return -EINVAL;
450                 }
451         }
452
453         dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n",
454                 timeout, divisor, count, DIV_ROUND_UP(count, divisor));
455
456         count = DIV_ROUND_UP(count, divisor);
457         wdt->count = count;
458
459         /* update the pre-scaler */
460         wtcon = readl(wdt->reg_base + S3C2410_WTCON);
461         wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
462         wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
463
464         writel(count, wdt->reg_base + S3C2410_WTDAT);
465         writel(wtcon, wdt->reg_base + S3C2410_WTCON);
466
467         wdd->timeout = (count * divisor) / freq;
468
469         return 0;
470 }
471
472 static int s3c2410wdt_restart(struct watchdog_device *wdd, unsigned long action,
473                               void *data)
474 {
475         struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
476         void __iomem *wdt_base = wdt->reg_base;
477
478         /* disable watchdog, to be safe  */
479         writel(0, wdt_base + S3C2410_WTCON);
480
481         /* put initial values into count and data */
482         writel(0x80, wdt_base + S3C2410_WTCNT);
483         writel(0x80, wdt_base + S3C2410_WTDAT);
484
485         /* set the watchdog to go and reset... */
486         writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
487                 S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
488                 wdt_base + S3C2410_WTCON);
489
490         /* wait for reset to assert... */
491         mdelay(500);
492
493         return 0;
494 }
495
496 #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
497
498 static const struct watchdog_info s3c2410_wdt_ident = {
499         .options          =     OPTIONS,
500         .firmware_version =     0,
501         .identity         =     "S3C2410 Watchdog",
502 };
503
504 static const struct watchdog_ops s3c2410wdt_ops = {
505         .owner = THIS_MODULE,
506         .start = s3c2410wdt_start,
507         .stop = s3c2410wdt_stop,
508         .ping = s3c2410wdt_keepalive,
509         .set_timeout = s3c2410wdt_set_heartbeat,
510         .restart = s3c2410wdt_restart,
511 };
512
513 static const struct watchdog_device s3c2410_wdd = {
514         .info = &s3c2410_wdt_ident,
515         .ops = &s3c2410wdt_ops,
516         .timeout = S3C2410_WATCHDOG_DEFAULT_TIME,
517 };
518
519 /* interrupt handler code */
520
521 static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
522 {
523         struct s3c2410_wdt *wdt = platform_get_drvdata(param);
524
525         dev_info(wdt->dev, "watchdog timer expired (irq)\n");
526
527         s3c2410wdt_keepalive(&wdt->wdt_device);
528
529         if (wdt->drv_data->quirks & QUIRK_HAS_WTCLRINT_REG)
530                 writel(0x1, wdt->reg_base + S3C2410_WTCLRINT);
531
532         return IRQ_HANDLED;
533 }
534
535 #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
536
537 static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
538                                           unsigned long val, void *data)
539 {
540         int ret;
541         struct s3c2410_wdt *wdt = freq_to_wdt(nb);
542
543         if (!s3c2410wdt_is_running(wdt))
544                 goto done;
545
546         if (val == CPUFREQ_PRECHANGE) {
547                 /* To ensure that over the change we don't cause the
548                  * watchdog to trigger, we perform an keep-alive if
549                  * the watchdog is running.
550                  */
551
552                 s3c2410wdt_keepalive(&wdt->wdt_device);
553         } else if (val == CPUFREQ_POSTCHANGE) {
554                 s3c2410wdt_stop(&wdt->wdt_device);
555
556                 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
557                                                 wdt->wdt_device.timeout);
558
559                 if (ret >= 0)
560                         s3c2410wdt_start(&wdt->wdt_device);
561                 else
562                         goto err;
563         }
564
565 done:
566         return 0;
567
568  err:
569         dev_err(wdt->dev, "cannot set new value for timeout %d\n",
570                                 wdt->wdt_device.timeout);
571         return ret;
572 }
573
574 static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt)
575 {
576         wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition;
577
578         return cpufreq_register_notifier(&wdt->freq_transition,
579                                          CPUFREQ_TRANSITION_NOTIFIER);
580 }
581
582 static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
583 {
584         wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition;
585
586         cpufreq_unregister_notifier(&wdt->freq_transition,
587                                     CPUFREQ_TRANSITION_NOTIFIER);
588 }
589
590 #else
591
592 static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt)
593 {
594         return 0;
595 }
596
597 static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
598 {
599 }
600 #endif
601
602 static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
603 {
604         unsigned int rst_stat;
605         int ret;
606
607         if (!(wdt->drv_data->quirks & QUIRK_HAS_PMU_RST_STAT))
608                 return 0;
609
610         ret = regmap_read(wdt->pmureg, wdt->drv_data->rst_stat_reg, &rst_stat);
611         if (ret)
612                 dev_warn(wdt->dev, "Couldn't get RST_STAT register\n");
613         else if (rst_stat & BIT(wdt->drv_data->rst_stat_bit))
614                 return WDIOF_CARDRESET;
615
616         return 0;
617 }
618
619 static inline const struct s3c2410_wdt_variant *
620 s3c2410_get_wdt_drv_data(struct platform_device *pdev)
621 {
622         const struct s3c2410_wdt_variant *variant;
623         struct device *dev = &pdev->dev;
624
625         variant = of_device_get_match_data(dev);
626         if (!variant) {
627                 /* Device matched by platform_device_id */
628                 variant = (struct s3c2410_wdt_variant *)
629                            platform_get_device_id(pdev)->driver_data;
630         }
631
632 #ifdef CONFIG_OF
633         /* Choose Exynos850 driver data w.r.t. cluster index */
634         if (variant == &drv_data_exynos850_cl0) {
635                 u32 index;
636                 int err;
637
638                 err = of_property_read_u32(dev->of_node,
639                                            "samsung,cluster-index", &index);
640                 if (err) {
641                         dev_err(dev, "failed to get cluster index\n");
642                         return NULL;
643                 }
644
645                 switch (index) {
646                 case 0:
647                         return &drv_data_exynos850_cl0;
648                 case 1:
649                         return &drv_data_exynos850_cl1;
650                 default:
651                         dev_err(dev, "wrong cluster index: %u\n", index);
652                         return NULL;
653                 }
654         }
655 #endif
656
657         return variant;
658 }
659
660 static int s3c2410wdt_probe(struct platform_device *pdev)
661 {
662         struct device *dev = &pdev->dev;
663         struct s3c2410_wdt *wdt;
664         unsigned int wtcon;
665         int wdt_irq;
666         int ret;
667
668         wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
669         if (!wdt)
670                 return -ENOMEM;
671
672         wdt->dev = dev;
673         spin_lock_init(&wdt->lock);
674         wdt->wdt_device = s3c2410_wdd;
675
676         wdt->drv_data = s3c2410_get_wdt_drv_data(pdev);
677         if (!wdt->drv_data)
678                 return -EINVAL;
679
680         if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
681                 wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
682                                                 "samsung,syscon-phandle");
683                 if (IS_ERR(wdt->pmureg)) {
684                         dev_err(dev, "syscon regmap lookup failed.\n");
685                         return PTR_ERR(wdt->pmureg);
686                 }
687         }
688
689         wdt_irq = platform_get_irq(pdev, 0);
690         if (wdt_irq < 0)
691                 return wdt_irq;
692
693         /* get the memory region for the watchdog timer */
694         wdt->reg_base = devm_platform_ioremap_resource(pdev, 0);
695         if (IS_ERR(wdt->reg_base))
696                 return PTR_ERR(wdt->reg_base);
697
698         wdt->bus_clk = devm_clk_get(dev, "watchdog");
699         if (IS_ERR(wdt->bus_clk)) {
700                 dev_err(dev, "failed to find bus clock\n");
701                 return PTR_ERR(wdt->bus_clk);
702         }
703
704         ret = clk_prepare_enable(wdt->bus_clk);
705         if (ret < 0) {
706                 dev_err(dev, "failed to enable bus clock\n");
707                 return ret;
708         }
709
710         /*
711          * "watchdog_src" clock is optional; if it's not present -- just skip it
712          * and use "watchdog" clock as both bus and source clock.
713          */
714         wdt->src_clk = devm_clk_get_optional(dev, "watchdog_src");
715         if (IS_ERR(wdt->src_clk)) {
716                 dev_err_probe(dev, PTR_ERR(wdt->src_clk),
717                               "failed to get source clock\n");
718                 ret = PTR_ERR(wdt->src_clk);
719                 goto err_bus_clk;
720         }
721
722         ret = clk_prepare_enable(wdt->src_clk);
723         if (ret) {
724                 dev_err(dev, "failed to enable source clock\n");
725                 goto err_bus_clk;
726         }
727
728         wdt->wdt_device.min_timeout = 1;
729         wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt);
730
731         ret = s3c2410wdt_cpufreq_register(wdt);
732         if (ret < 0) {
733                 dev_err(dev, "failed to register cpufreq\n");
734                 goto err_src_clk;
735         }
736
737         watchdog_set_drvdata(&wdt->wdt_device, wdt);
738
739         /* see if we can actually set the requested timer margin, and if
740          * not, try the default value */
741
742         watchdog_init_timeout(&wdt->wdt_device, tmr_margin, dev);
743         ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
744                                         wdt->wdt_device.timeout);
745         if (ret) {
746                 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
747                                                S3C2410_WATCHDOG_DEFAULT_TIME);
748                 if (ret == 0) {
749                         dev_warn(dev, "tmr_margin value out of range, default %d used\n",
750                                  S3C2410_WATCHDOG_DEFAULT_TIME);
751                 } else {
752                         dev_err(dev, "failed to use default timeout\n");
753                         goto err_cpufreq;
754                 }
755         }
756
757         ret = devm_request_irq(dev, wdt_irq, s3c2410wdt_irq, 0,
758                                pdev->name, pdev);
759         if (ret != 0) {
760                 dev_err(dev, "failed to install irq (%d)\n", ret);
761                 goto err_cpufreq;
762         }
763
764         watchdog_set_nowayout(&wdt->wdt_device, nowayout);
765         watchdog_set_restart_priority(&wdt->wdt_device, 128);
766
767         wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt);
768         wdt->wdt_device.parent = dev;
769
770         /*
771          * If "tmr_atboot" param is non-zero, start the watchdog right now. Also
772          * set WDOG_HW_RUNNING bit, so that watchdog core can kick the watchdog.
773          *
774          * If we're not enabling the watchdog, then ensure it is disabled if it
775          * has been left running from the bootloader or other source.
776          */
777         if (tmr_atboot) {
778                 dev_info(dev, "starting watchdog timer\n");
779                 s3c2410wdt_start(&wdt->wdt_device);
780                 set_bit(WDOG_HW_RUNNING, &wdt->wdt_device.status);
781         } else {
782                 s3c2410wdt_stop(&wdt->wdt_device);
783         }
784
785         ret = watchdog_register_device(&wdt->wdt_device);
786         if (ret)
787                 goto err_cpufreq;
788
789         ret = s3c2410wdt_enable(wdt, true);
790         if (ret < 0)
791                 goto err_unregister;
792
793         platform_set_drvdata(pdev, wdt);
794
795         /* print out a statement of readiness */
796
797         wtcon = readl(wdt->reg_base + S3C2410_WTCON);
798
799         dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
800                  (wtcon & S3C2410_WTCON_ENABLE) ?  "" : "in",
801                  (wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis",
802                  (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis");
803
804         return 0;
805
806  err_unregister:
807         watchdog_unregister_device(&wdt->wdt_device);
808
809  err_cpufreq:
810         s3c2410wdt_cpufreq_deregister(wdt);
811
812  err_src_clk:
813         clk_disable_unprepare(wdt->src_clk);
814
815  err_bus_clk:
816         clk_disable_unprepare(wdt->bus_clk);
817
818         return ret;
819 }
820
821 static int s3c2410wdt_remove(struct platform_device *dev)
822 {
823         int ret;
824         struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
825
826         ret = s3c2410wdt_enable(wdt, false);
827         if (ret < 0)
828                 return ret;
829
830         watchdog_unregister_device(&wdt->wdt_device);
831
832         s3c2410wdt_cpufreq_deregister(wdt);
833
834         clk_disable_unprepare(wdt->src_clk);
835         clk_disable_unprepare(wdt->bus_clk);
836
837         return 0;
838 }
839
840 static void s3c2410wdt_shutdown(struct platform_device *dev)
841 {
842         struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
843
844         s3c2410wdt_enable(wdt, false);
845         s3c2410wdt_stop(&wdt->wdt_device);
846 }
847
848 #ifdef CONFIG_PM_SLEEP
849
850 static int s3c2410wdt_suspend(struct device *dev)
851 {
852         int ret;
853         struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
854
855         /* Save watchdog state, and turn it off. */
856         wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON);
857         wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT);
858
859         ret = s3c2410wdt_enable(wdt, false);
860         if (ret < 0)
861                 return ret;
862
863         /* Note that WTCNT doesn't need to be saved. */
864         s3c2410wdt_stop(&wdt->wdt_device);
865
866         return 0;
867 }
868
869 static int s3c2410wdt_resume(struct device *dev)
870 {
871         int ret;
872         struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
873
874         /* Restore watchdog state. */
875         writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTDAT);
876         writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */
877         writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON);
878
879         ret = s3c2410wdt_enable(wdt, true);
880         if (ret < 0)
881                 return ret;
882
883         dev_info(dev, "watchdog %sabled\n",
884                 (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
885
886         return 0;
887 }
888 #endif
889
890 static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend,
891                         s3c2410wdt_resume);
892
893 static struct platform_driver s3c2410wdt_driver = {
894         .probe          = s3c2410wdt_probe,
895         .remove         = s3c2410wdt_remove,
896         .shutdown       = s3c2410wdt_shutdown,
897         .id_table       = s3c2410_wdt_ids,
898         .driver         = {
899                 .name   = "s3c2410-wdt",
900                 .pm     = &s3c2410wdt_pm_ops,
901                 .of_match_table = of_match_ptr(s3c2410_wdt_match),
902         },
903 };
904
905 module_platform_driver(s3c2410wdt_driver);
906
907 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Dimitry Andric <dimitry.andric@tomtom.com>");
908 MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
909 MODULE_LICENSE("GPL");