1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Renesas RZ/A Series WDT Driver |
4 | * |
5 | * Copyright (C) 2017 Renesas Electronics America, Inc. |
6 | * Copyright (C) 2017 Chris Brandt |
7 | */ |
8 | |
9 | #include <linux/bitops.h> |
10 | #include <linux/clk.h> |
11 | #include <linux/delay.h> |
12 | #include <linux/io.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/watchdog.h> |
17 | |
18 | #define DEFAULT_TIMEOUT 30 |
19 | |
20 | /* Watchdog Timer Registers */ |
21 | #define WTCSR 0 |
22 | #define WTCSR_MAGIC 0xA500 |
23 | #define WTSCR_WT BIT(6) |
24 | #define WTSCR_TME BIT(5) |
25 | #define WTSCR_CKS(i) (i) |
26 | |
27 | #define WTCNT 2 |
28 | #define WTCNT_MAGIC 0x5A00 |
29 | |
30 | #define WRCSR 4 |
31 | #define WRCSR_MAGIC 0x5A00 |
32 | #define WRCSR_RSTE BIT(6) |
33 | #define WRCSR_CLEAR_WOVF 0xA500 /* special value */ |
34 | |
35 | /* The maximum CKS register setting value to get the longest timeout */ |
36 | #define CKS_3BIT 0x7 |
37 | #define CKS_4BIT 0xF |
38 | |
39 | #define DIVIDER_3BIT 16384 /* Clock divider when CKS = 0x7 */ |
40 | #define DIVIDER_4BIT 4194304 /* Clock divider when CKS = 0xF */ |
41 | |
42 | struct rza_wdt { |
43 | struct watchdog_device wdev; |
44 | void __iomem *base; |
45 | struct clk *clk; |
46 | u8 count; |
47 | u8 cks; |
48 | }; |
49 | |
50 | static void rza_wdt_calc_timeout(struct rza_wdt *priv, int timeout) |
51 | { |
52 | unsigned long rate = clk_get_rate(clk: priv->clk); |
53 | unsigned int ticks; |
54 | |
55 | if (priv->cks == CKS_4BIT) { |
56 | ticks = DIV_ROUND_UP(timeout * rate, DIVIDER_4BIT); |
57 | |
58 | /* |
59 | * Since max_timeout was set in probe, we know that the timeout |
60 | * value passed will never calculate to a tick value greater |
61 | * than 256. |
62 | */ |
63 | priv->count = 256 - ticks; |
64 | |
65 | } else { |
66 | /* Start timer with longest timeout */ |
67 | priv->count = 0; |
68 | } |
69 | |
70 | pr_debug("%s: timeout set to %u (WTCNT=%d)\n" , __func__, |
71 | timeout, priv->count); |
72 | } |
73 | |
74 | static int rza_wdt_start(struct watchdog_device *wdev) |
75 | { |
76 | struct rza_wdt *priv = watchdog_get_drvdata(wdd: wdev); |
77 | |
78 | /* Stop timer */ |
79 | writew(WTCSR_MAGIC | 0, addr: priv->base + WTCSR); |
80 | |
81 | /* Must dummy read WRCSR:WOVF at least once before clearing */ |
82 | readb(addr: priv->base + WRCSR); |
83 | writew(WRCSR_CLEAR_WOVF, addr: priv->base + WRCSR); |
84 | |
85 | rza_wdt_calc_timeout(priv, timeout: wdev->timeout); |
86 | |
87 | writew(WRCSR_MAGIC | WRCSR_RSTE, addr: priv->base + WRCSR); |
88 | writew(WTCNT_MAGIC | priv->count, addr: priv->base + WTCNT); |
89 | writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME | |
90 | WTSCR_CKS(priv->cks), addr: priv->base + WTCSR); |
91 | |
92 | return 0; |
93 | } |
94 | |
95 | static int rza_wdt_stop(struct watchdog_device *wdev) |
96 | { |
97 | struct rza_wdt *priv = watchdog_get_drvdata(wdd: wdev); |
98 | |
99 | writew(WTCSR_MAGIC | 0, addr: priv->base + WTCSR); |
100 | |
101 | return 0; |
102 | } |
103 | |
104 | static int rza_wdt_ping(struct watchdog_device *wdev) |
105 | { |
106 | struct rza_wdt *priv = watchdog_get_drvdata(wdd: wdev); |
107 | |
108 | writew(WTCNT_MAGIC | priv->count, addr: priv->base + WTCNT); |
109 | |
110 | pr_debug("%s: timeout = %u\n" , __func__, wdev->timeout); |
111 | |
112 | return 0; |
113 | } |
114 | |
115 | static int rza_set_timeout(struct watchdog_device *wdev, unsigned int timeout) |
116 | { |
117 | wdev->timeout = timeout; |
118 | rza_wdt_start(wdev); |
119 | return 0; |
120 | } |
121 | |
122 | static int rza_wdt_restart(struct watchdog_device *wdev, unsigned long action, |
123 | void *data) |
124 | { |
125 | struct rza_wdt *priv = watchdog_get_drvdata(wdd: wdev); |
126 | |
127 | /* Stop timer */ |
128 | writew(WTCSR_MAGIC | 0, addr: priv->base + WTCSR); |
129 | |
130 | /* Must dummy read WRCSR:WOVF at least once before clearing */ |
131 | readb(addr: priv->base + WRCSR); |
132 | writew(WRCSR_CLEAR_WOVF, addr: priv->base + WRCSR); |
133 | |
134 | /* |
135 | * Start timer with fastest clock source and only 1 clock left before |
136 | * overflow with reset option enabled. |
137 | */ |
138 | writew(WRCSR_MAGIC | WRCSR_RSTE, addr: priv->base + WRCSR); |
139 | writew(WTCNT_MAGIC | 255, addr: priv->base + WTCNT); |
140 | writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME, addr: priv->base + WTCSR); |
141 | |
142 | /* |
143 | * Actually make sure the above sequence hits hardware before sleeping. |
144 | */ |
145 | wmb(); |
146 | |
147 | /* Wait for WDT overflow (reset) */ |
148 | udelay(20); |
149 | |
150 | return 0; |
151 | } |
152 | |
153 | static const struct watchdog_info rza_wdt_ident = { |
154 | .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, |
155 | .identity = "Renesas RZ/A WDT Watchdog" , |
156 | }; |
157 | |
158 | static const struct watchdog_ops rza_wdt_ops = { |
159 | .owner = THIS_MODULE, |
160 | .start = rza_wdt_start, |
161 | .stop = rza_wdt_stop, |
162 | .ping = rza_wdt_ping, |
163 | .set_timeout = rza_set_timeout, |
164 | .restart = rza_wdt_restart, |
165 | }; |
166 | |
167 | static int rza_wdt_probe(struct platform_device *pdev) |
168 | { |
169 | struct device *dev = &pdev->dev; |
170 | struct rza_wdt *priv; |
171 | unsigned long rate; |
172 | int ret; |
173 | |
174 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
175 | if (!priv) |
176 | return -ENOMEM; |
177 | |
178 | priv->base = devm_platform_ioremap_resource(pdev, index: 0); |
179 | if (IS_ERR(ptr: priv->base)) |
180 | return PTR_ERR(ptr: priv->base); |
181 | |
182 | priv->clk = devm_clk_get(dev, NULL); |
183 | if (IS_ERR(ptr: priv->clk)) |
184 | return PTR_ERR(ptr: priv->clk); |
185 | |
186 | rate = clk_get_rate(clk: priv->clk); |
187 | if (rate < 16384) { |
188 | dev_err(dev, "invalid clock rate (%ld)\n" , rate); |
189 | return -ENOENT; |
190 | } |
191 | |
192 | priv->wdev.info = &rza_wdt_ident; |
193 | priv->wdev.ops = &rza_wdt_ops; |
194 | priv->wdev.parent = dev; |
195 | |
196 | priv->cks = (u8)(uintptr_t) of_device_get_match_data(dev); |
197 | if (priv->cks == CKS_4BIT) { |
198 | /* Assume slowest clock rate possible (CKS=0xF) */ |
199 | priv->wdev.max_timeout = (DIVIDER_4BIT * U8_MAX) / rate; |
200 | |
201 | } else if (priv->cks == CKS_3BIT) { |
202 | /* Assume slowest clock rate possible (CKS=7) */ |
203 | rate /= DIVIDER_3BIT; |
204 | |
205 | /* |
206 | * Since the max possible timeout of our 8-bit count |
207 | * register is less than a second, we must use |
208 | * max_hw_heartbeat_ms. |
209 | */ |
210 | priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate; |
211 | dev_dbg(dev, "max hw timeout of %dms\n" , |
212 | priv->wdev.max_hw_heartbeat_ms); |
213 | } |
214 | |
215 | priv->wdev.min_timeout = 1; |
216 | priv->wdev.timeout = DEFAULT_TIMEOUT; |
217 | |
218 | watchdog_init_timeout(wdd: &priv->wdev, timeout_parm: 0, dev); |
219 | watchdog_set_drvdata(wdd: &priv->wdev, data: priv); |
220 | |
221 | ret = devm_watchdog_register_device(dev, &priv->wdev); |
222 | if (ret) |
223 | dev_err(dev, "Cannot register watchdog device\n" ); |
224 | |
225 | return ret; |
226 | } |
227 | |
228 | static const struct of_device_id rza_wdt_of_match[] = { |
229 | { .compatible = "renesas,r7s9210-wdt" , .data = (void *)CKS_4BIT, }, |
230 | { .compatible = "renesas,rza-wdt" , .data = (void *)CKS_3BIT, }, |
231 | { /* sentinel */ } |
232 | }; |
233 | MODULE_DEVICE_TABLE(of, rza_wdt_of_match); |
234 | |
235 | static struct platform_driver rza_wdt_driver = { |
236 | .probe = rza_wdt_probe, |
237 | .driver = { |
238 | .name = "rza_wdt" , |
239 | .of_match_table = rza_wdt_of_match, |
240 | }, |
241 | }; |
242 | |
243 | module_platform_driver(rza_wdt_driver); |
244 | |
245 | MODULE_DESCRIPTION("Renesas RZ/A WDT Driver" ); |
246 | MODULE_AUTHOR("Chris Brandt <chris.brandt@renesas.com>" ); |
247 | MODULE_LICENSE("GPL v2" ); |
248 | |