.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * Renesas RZ/A Series WDT Driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2017 Renesas Electronics America, Inc. |
---|
5 | 6 | * Copyright (C) 2017 Chris Brandt |
---|
6 | | - * |
---|
7 | | - * This file is subject to the terms and conditions of the GNU General Public |
---|
8 | | - * License. See the file "COPYING" in the main directory of this archive |
---|
9 | | - * for more details. |
---|
10 | 7 | */ |
---|
11 | 8 | |
---|
12 | 9 | #include <linux/bitops.h> |
---|
.. | .. |
---|
14 | 11 | #include <linux/delay.h> |
---|
15 | 12 | #include <linux/module.h> |
---|
16 | 13 | #include <linux/of_address.h> |
---|
| 14 | +#include <linux/of_device.h> |
---|
17 | 15 | #include <linux/platform_device.h> |
---|
18 | 16 | #include <linux/watchdog.h> |
---|
19 | 17 | |
---|
.. | .. |
---|
34 | 32 | #define WRCSR_RSTE BIT(6) |
---|
35 | 33 | #define WRCSR_CLEAR_WOVF 0xA500 /* special value */ |
---|
36 | 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 | + |
---|
37 | 42 | struct rza_wdt { |
---|
38 | 43 | struct watchdog_device wdev; |
---|
39 | 44 | void __iomem *base; |
---|
40 | 45 | struct clk *clk; |
---|
| 46 | + u8 count; |
---|
| 47 | + u8 cks; |
---|
41 | 48 | }; |
---|
| 49 | + |
---|
| 50 | +static void rza_wdt_calc_timeout(struct rza_wdt *priv, int timeout) |
---|
| 51 | +{ |
---|
| 52 | + unsigned long rate = clk_get_rate(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 | +} |
---|
42 | 73 | |
---|
43 | 74 | static int rza_wdt_start(struct watchdog_device *wdev) |
---|
44 | 75 | { |
---|
.. | .. |
---|
51 | 82 | readb(priv->base + WRCSR); |
---|
52 | 83 | writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR); |
---|
53 | 84 | |
---|
54 | | - /* |
---|
55 | | - * Start timer with slowest clock source and reset option enabled. |
---|
56 | | - */ |
---|
| 85 | + rza_wdt_calc_timeout(priv, wdev->timeout); |
---|
| 86 | + |
---|
57 | 87 | writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR); |
---|
58 | | - writew(WTCNT_MAGIC | 0, priv->base + WTCNT); |
---|
59 | | - writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME | WTSCR_CKS(7), |
---|
60 | | - priv->base + WTCSR); |
---|
| 88 | + writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT); |
---|
| 89 | + writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME | |
---|
| 90 | + WTSCR_CKS(priv->cks), priv->base + WTCSR); |
---|
61 | 91 | |
---|
62 | 92 | return 0; |
---|
63 | 93 | } |
---|
.. | .. |
---|
75 | 105 | { |
---|
76 | 106 | struct rza_wdt *priv = watchdog_get_drvdata(wdev); |
---|
77 | 107 | |
---|
78 | | - writew(WTCNT_MAGIC | 0, priv->base + WTCNT); |
---|
| 108 | + writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT); |
---|
79 | 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); |
---|
80 | 119 | return 0; |
---|
81 | 120 | } |
---|
82 | 121 | |
---|
.. | .. |
---|
121 | 160 | .start = rza_wdt_start, |
---|
122 | 161 | .stop = rza_wdt_stop, |
---|
123 | 162 | .ping = rza_wdt_ping, |
---|
| 163 | + .set_timeout = rza_set_timeout, |
---|
124 | 164 | .restart = rza_wdt_restart, |
---|
125 | 165 | }; |
---|
126 | 166 | |
---|
127 | 167 | static int rza_wdt_probe(struct platform_device *pdev) |
---|
128 | 168 | { |
---|
| 169 | + struct device *dev = &pdev->dev; |
---|
129 | 170 | struct rza_wdt *priv; |
---|
130 | | - struct resource *res; |
---|
131 | 171 | unsigned long rate; |
---|
132 | 172 | int ret; |
---|
133 | 173 | |
---|
134 | | - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
---|
| 174 | + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
---|
135 | 175 | if (!priv) |
---|
136 | 176 | return -ENOMEM; |
---|
137 | 177 | |
---|
138 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
139 | | - priv->base = devm_ioremap_resource(&pdev->dev, res); |
---|
| 178 | + priv->base = devm_platform_ioremap_resource(pdev, 0); |
---|
140 | 179 | if (IS_ERR(priv->base)) |
---|
141 | 180 | return PTR_ERR(priv->base); |
---|
142 | 181 | |
---|
143 | | - priv->clk = devm_clk_get(&pdev->dev, NULL); |
---|
| 182 | + priv->clk = devm_clk_get(dev, NULL); |
---|
144 | 183 | if (IS_ERR(priv->clk)) |
---|
145 | 184 | return PTR_ERR(priv->clk); |
---|
146 | 185 | |
---|
147 | 186 | rate = clk_get_rate(priv->clk); |
---|
148 | 187 | if (rate < 16384) { |
---|
149 | | - dev_err(&pdev->dev, "invalid clock rate (%ld)\n", rate); |
---|
| 188 | + dev_err(dev, "invalid clock rate (%ld)\n", rate); |
---|
150 | 189 | return -ENOENT; |
---|
151 | 190 | } |
---|
152 | 191 | |
---|
153 | | - /* Assume slowest clock rate possible (CKS=7) */ |
---|
154 | | - rate /= 16384; |
---|
155 | | - |
---|
156 | 192 | priv->wdev.info = &rza_wdt_ident, |
---|
157 | 193 | priv->wdev.ops = &rza_wdt_ops, |
---|
158 | | - priv->wdev.parent = &pdev->dev; |
---|
| 194 | + priv->wdev.parent = dev; |
---|
159 | 195 | |
---|
160 | | - /* |
---|
161 | | - * Since the max possible timeout of our 8-bit count register is less |
---|
162 | | - * than a second, we must use max_hw_heartbeat_ms. |
---|
163 | | - */ |
---|
164 | | - priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate; |
---|
165 | | - dev_dbg(&pdev->dev, "max hw timeout of %dms\n", |
---|
166 | | - priv->wdev.max_hw_heartbeat_ms); |
---|
| 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 | + } |
---|
167 | 214 | |
---|
168 | 215 | priv->wdev.min_timeout = 1; |
---|
169 | 216 | priv->wdev.timeout = DEFAULT_TIMEOUT; |
---|
170 | 217 | |
---|
171 | | - watchdog_init_timeout(&priv->wdev, 0, &pdev->dev); |
---|
| 218 | + watchdog_init_timeout(&priv->wdev, 0, dev); |
---|
172 | 219 | watchdog_set_drvdata(&priv->wdev, priv); |
---|
173 | 220 | |
---|
174 | | - ret = devm_watchdog_register_device(&pdev->dev, &priv->wdev); |
---|
| 221 | + ret = devm_watchdog_register_device(dev, &priv->wdev); |
---|
175 | 222 | if (ret) |
---|
176 | | - dev_err(&pdev->dev, "Cannot register watchdog device\n"); |
---|
| 223 | + dev_err(dev, "Cannot register watchdog device\n"); |
---|
177 | 224 | |
---|
178 | 225 | return ret; |
---|
179 | 226 | } |
---|
180 | 227 | |
---|
181 | 228 | static const struct of_device_id rza_wdt_of_match[] = { |
---|
182 | | - { .compatible = "renesas,rza-wdt", }, |
---|
| 229 | + { .compatible = "renesas,r7s9210-wdt", .data = (void *)CKS_4BIT, }, |
---|
| 230 | + { .compatible = "renesas,rza-wdt", .data = (void *)CKS_3BIT, }, |
---|
183 | 231 | { /* sentinel */ } |
---|
184 | 232 | }; |
---|
185 | 233 | MODULE_DEVICE_TABLE(of, rza_wdt_of_match); |
---|