]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
77331934 ÁFR |
2 | /* |
3 | * Copyright (C) 2017 Álvaro Fernández Rojas <[email protected]> | |
4 | * | |
5 | * Derived from linux/drivers/watchdog/bcm63xx_wdt.c: | |
6 | * Copyright (C) 2007 Miguel Gaio <[email protected]> | |
7 | * Copyright (C) 2008 Florian Fainelli <[email protected]> | |
77331934 ÁFR |
8 | */ |
9 | ||
77331934 | 10 | #include <dm.h> |
f7ae49fc | 11 | #include <log.h> |
77331934 | 12 | #include <wdt.h> |
c411adbd | 13 | #include <clk.h> |
77331934 ÁFR |
14 | #include <asm/io.h> |
15 | ||
16 | /* WDT Value register */ | |
17 | #define WDT_VAL_REG 0x0 | |
18 | #define WDT_VAL_MIN 0x00000002 | |
19 | #define WDT_VAL_MAX 0xfffffffe | |
20 | ||
21 | /* WDT Control register */ | |
22 | #define WDT_CTL_REG 0x4 | |
23 | #define WDT_CTL_START1_MASK 0x0000ff00 | |
24 | #define WDT_CTL_START2_MASK 0x000000ff | |
25 | #define WDT_CTL_STOP1_MASK 0x0000ee00 | |
26 | #define WDT_CTL_STOP2_MASK 0x000000ee | |
27 | ||
28 | struct bcm6345_wdt_priv { | |
29 | void __iomem *regs; | |
c411adbd | 30 | unsigned long clk_rate; |
77331934 ÁFR |
31 | }; |
32 | ||
33 | static int bcm6345_wdt_reset(struct udevice *dev) | |
34 | { | |
35 | struct bcm6345_wdt_priv *priv = dev_get_priv(dev); | |
36 | ||
771ee9b6 PR |
37 | writel(WDT_CTL_START1_MASK, priv->regs + WDT_CTL_REG); |
38 | writel(WDT_CTL_START2_MASK, priv->regs + WDT_CTL_REG); | |
77331934 ÁFR |
39 | |
40 | return 0; | |
41 | } | |
42 | ||
43 | static int bcm6345_wdt_start(struct udevice *dev, u64 timeout, ulong flags) | |
44 | { | |
45 | struct bcm6345_wdt_priv *priv = dev_get_priv(dev); | |
c411adbd | 46 | u32 val = priv->clk_rate / 1000 * timeout; |
77331934 | 47 | |
c411adbd | 48 | if (val < WDT_VAL_MIN) { |
77331934 | 49 | debug("watchdog won't fire with less than 2 ticks\n"); |
c411adbd PR |
50 | val = WDT_VAL_MIN; |
51 | } else if (val > WDT_VAL_MAX) { | |
77331934 | 52 | debug("maximum watchdog timeout exceeded\n"); |
c411adbd | 53 | val = WDT_VAL_MAX; |
77331934 ÁFR |
54 | } |
55 | ||
c411adbd | 56 | writel(val, priv->regs + WDT_VAL_REG); |
77331934 ÁFR |
57 | |
58 | return bcm6345_wdt_reset(dev); | |
59 | } | |
60 | ||
61 | static int bcm6345_wdt_expire_now(struct udevice *dev, ulong flags) | |
62 | { | |
63 | return bcm6345_wdt_start(dev, WDT_VAL_MIN, flags); | |
64 | } | |
65 | ||
66 | static int bcm6345_wdt_stop(struct udevice *dev) | |
67 | { | |
68 | struct bcm6345_wdt_priv *priv = dev_get_priv(dev); | |
69 | ||
771ee9b6 PR |
70 | writel(WDT_CTL_STOP1_MASK, priv->regs + WDT_CTL_REG); |
71 | writel(WDT_CTL_STOP2_MASK, priv->regs + WDT_CTL_REG); | |
77331934 ÁFR |
72 | |
73 | return 0; | |
74 | } | |
75 | ||
76 | static const struct wdt_ops bcm6345_wdt_ops = { | |
77 | .expire_now = bcm6345_wdt_expire_now, | |
78 | .reset = bcm6345_wdt_reset, | |
79 | .start = bcm6345_wdt_start, | |
80 | .stop = bcm6345_wdt_stop, | |
81 | }; | |
82 | ||
83 | static const struct udevice_id bcm6345_wdt_ids[] = { | |
84 | { .compatible = "brcm,bcm6345-wdt" }, | |
85 | { /* sentinel */ } | |
86 | }; | |
87 | ||
88 | static int bcm6345_wdt_probe(struct udevice *dev) | |
89 | { | |
90 | struct bcm6345_wdt_priv *priv = dev_get_priv(dev); | |
c411adbd PR |
91 | struct clk clk; |
92 | int ret; | |
77331934 | 93 | |
aa8f8250 ÁFR |
94 | priv->regs = dev_remap_addr(dev); |
95 | if (!priv->regs) | |
77331934 ÁFR |
96 | return -EINVAL; |
97 | ||
c411adbd PR |
98 | ret = clk_get_by_index(dev, 0, &clk); |
99 | if (!ret) | |
100 | priv->clk_rate = clk_get_rate(&clk); | |
101 | else | |
102 | return -EINVAL; | |
103 | ||
77331934 ÁFR |
104 | bcm6345_wdt_stop(dev); |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | U_BOOT_DRIVER(wdt_bcm6345) = { | |
110 | .name = "wdt_bcm6345", | |
111 | .id = UCLASS_WDT, | |
112 | .of_match = bcm6345_wdt_ids, | |
113 | .ops = &bcm6345_wdt_ops, | |
41575d8e | 114 | .priv_auto = sizeof(struct bcm6345_wdt_priv), |
77331934 ÁFR |
115 | .probe = bcm6345_wdt_probe, |
116 | }; |