Skip to content

Commit 2b20697

Browse files
prabhakarladWim Van Sebroeck
authored andcommitted
watchdog: rzv2h: Add support for RZ/T2H
Add support for the RZ/T2H watchdog timer. The RZ/T2H requires control of the watchdog counter using the WDT Debug Control Register (WDTDCR), which allows explicitly stopping and starting the counter. This behavior differs from RZ/V2H, which doesn't have WDTDCR, so the driver is extended to handle this requirement. To support this, a new `wdtdcr` flag is introduced in the `rzv2h_of_data` structure. When set, the driver maps the WDTDCR register and uses it to control the watchdog counter in the start, stop, and restart callbacks. Additionally, the clock divisor and count source for RZ/T2H are defined to match its hardware configuration. Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
1 parent ef6080f commit 2b20697

File tree

1 file changed

+81
-3
lines changed

1 file changed

+81
-3
lines changed

drivers/watchdog/rzv2h_wdt.c

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,17 @@
2121
#define WDTSR 0x04 /* WDT Status Register RW, 16 */
2222
#define WDTRCR 0x06 /* WDT Reset Control Register RW, 8 */
2323

24+
/* This register is only available on RZ/T2H and RZ/N2H SoCs */
25+
#define WDTDCR 0x00 /* WDT Debug Control Register RW, 32 */
26+
2427
#define WDTCR_TOPS_1024 0x00
28+
#define WDTCR_TOPS_4096 0x01
2529
#define WDTCR_TOPS_16384 0x03
2630

2731
#define WDTCR_CKS_CLK_1 0x00
32+
#define WDTCR_CKS_CLK_4 0x10
2833
#define WDTCR_CKS_CLK_256 0x50
34+
#define WDTCR_CKS_CLK_8192 0x80
2935

3036
#define WDTCR_RPES_0 0x300
3137
#define WDTCR_RPES_75 0x000
@@ -35,6 +41,8 @@
3541

3642
#define WDTRCR_RSTIRQS BIT(7)
3743

44+
#define WDTDCR_WDTSTOPCTRL BIT(0)
45+
3846
#define WDT_DEFAULT_TIMEOUT 60U
3947

4048
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -54,10 +62,12 @@ struct rzv2h_of_data {
5462
u8 tops;
5563
u16 timeout_cycles;
5664
enum rzv2h_wdt_count_source count_source;
65+
bool wdtdcr;
5766
};
5867

5968
struct rzv2h_wdt_priv {
6069
void __iomem *base;
70+
void __iomem *wdtdcr;
6171
struct clk *pclk;
6272
struct clk *oscclk;
6373
struct reset_control *rstc;
@@ -79,6 +89,20 @@ static int rzv2h_wdt_ping(struct watchdog_device *wdev)
7989
return 0;
8090
}
8191

92+
static void rzt2h_wdt_wdtdcr_count_stop(struct rzv2h_wdt_priv *priv)
93+
{
94+
u32 reg = readl(priv->wdtdcr + WDTDCR);
95+
96+
writel(reg | WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR);
97+
}
98+
99+
static void rzt2h_wdt_wdtdcr_count_start(struct rzv2h_wdt_priv *priv)
100+
{
101+
u32 reg = readl(priv->wdtdcr + WDTDCR);
102+
103+
writel(reg & ~WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR);
104+
}
105+
82106
static void rzv2h_wdt_setup(struct watchdog_device *wdev, u16 wdtcr)
83107
{
84108
struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev);
@@ -114,14 +138,21 @@ static int rzv2h_wdt_start(struct watchdog_device *wdev)
114138

115139
/*
116140
* WDTCR
117-
* - CKS[7:4] - Clock Division Ratio Select - 0101b: oscclk/256
141+
* - CKS[7:4] - Clock Division Ratio Select
142+
* - 0101b: oscclk/256 for RZ/V2H(P)
143+
* - 1000b: pclkl/8192 for RZ/T2H
118144
* - RPSS[13:12] - Window Start Position Select - 11b: 100%
119145
* - RPES[9:8] - Window End Position Select - 11b: 0%
120-
* - TOPS[1:0] - Timeout Period Select - 11b: 16384 cycles (3FFFh)
146+
* - TOPS[1:0] - Timeout Period Select
147+
* - 11b: 16384 cycles (3FFFh) for RZ/V2H(P)
148+
* - 01b: 4096 cycles (0FFFh) for RZ/T2H
121149
*/
122150
rzv2h_wdt_setup(wdev, of_data->cks_max | WDTCR_RPSS_100 |
123151
WDTCR_RPES_0 | of_data->tops);
124152

153+
if (priv->of_data->wdtdcr)
154+
rzt2h_wdt_wdtdcr_count_start(priv);
155+
125156
/*
126157
* Down counting starts after writing the sequence 00h -> FFh to the
127158
* WDTRR register. Hence, call the ping operation after loading the counter.
@@ -140,6 +171,9 @@ static int rzv2h_wdt_stop(struct watchdog_device *wdev)
140171
if (ret)
141172
return ret;
142173

174+
if (priv->of_data->wdtdcr)
175+
rzt2h_wdt_wdtdcr_count_stop(priv);
176+
143177
ret = pm_runtime_put(wdev->parent);
144178
if (ret < 0)
145179
return ret;
@@ -192,14 +226,19 @@ static int rzv2h_wdt_restart(struct watchdog_device *wdev,
192226

193227
/*
194228
* WDTCR
195-
* - CKS[7:4] - Clock Division Ratio Select - 0000b: oscclk/1
229+
* - CKS[7:4] - Clock Division Ratio Select
230+
* - 0000b: oscclk/1 for RZ/V2H(P)
231+
* - 0100b: pclkl/4 for RZ/T2H
196232
* - RPSS[13:12] - Window Start Position Select - 00b: 25%
197233
* - RPES[9:8] - Window End Position Select - 00b: 75%
198234
* - TOPS[1:0] - Timeout Period Select - 00b: 1024 cycles (03FFh)
199235
*/
200236
rzv2h_wdt_setup(wdev, priv->of_data->cks_min | WDTCR_RPSS_25 |
201237
WDTCR_RPES_75 | WDTCR_TOPS_1024);
202238

239+
if (priv->of_data->wdtdcr)
240+
rzt2h_wdt_wdtdcr_count_start(priv);
241+
203242
rzv2h_wdt_ping(wdev);
204243

205244
/* wait for underflow to trigger... */
@@ -216,6 +255,28 @@ static const struct watchdog_ops rzv2h_wdt_ops = {
216255
.restart = rzv2h_wdt_restart,
217256
};
218257

258+
static int rzt2h_wdt_wdtdcr_init(struct platform_device *pdev,
259+
struct rzv2h_wdt_priv *priv)
260+
{
261+
int ret;
262+
263+
priv->wdtdcr = devm_platform_ioremap_resource(pdev, 1);
264+
if (IS_ERR(priv->wdtdcr))
265+
return PTR_ERR(priv->wdtdcr);
266+
267+
ret = pm_runtime_resume_and_get(&pdev->dev);
268+
if (ret)
269+
return ret;
270+
271+
rzt2h_wdt_wdtdcr_count_stop(priv);
272+
273+
ret = pm_runtime_put(&pdev->dev);
274+
if (ret < 0)
275+
return ret;
276+
277+
return 0;
278+
}
279+
219280
static int rzv2h_wdt_probe(struct platform_device *pdev)
220281
{
221282
struct device *dev = &pdev->dev;
@@ -265,6 +326,12 @@ static int rzv2h_wdt_probe(struct platform_device *pdev)
265326
if (ret)
266327
return ret;
267328

329+
if (priv->of_data->wdtdcr) {
330+
ret = rzt2h_wdt_wdtdcr_init(pdev, priv);
331+
if (ret)
332+
return dev_err_probe(dev, ret, "WDTDCR init failed\n");
333+
}
334+
268335
priv->wdev.min_timeout = 1;
269336
priv->wdev.timeout = WDT_DEFAULT_TIMEOUT;
270337
priv->wdev.info = &rzv2h_wdt_ident;
@@ -281,6 +348,16 @@ static int rzv2h_wdt_probe(struct platform_device *pdev)
281348
return devm_watchdog_register_device(dev, &priv->wdev);
282349
}
283350

351+
static const struct rzv2h_of_data rzt2h_wdt_of_data = {
352+
.cks_min = WDTCR_CKS_CLK_4,
353+
.cks_max = WDTCR_CKS_CLK_8192,
354+
.cks_div = 8192,
355+
.tops = WDTCR_TOPS_4096,
356+
.timeout_cycles = 4096,
357+
.count_source = COUNT_SOURCE_PCLK,
358+
.wdtdcr = true,
359+
};
360+
284361
static const struct rzv2h_of_data rzv2h_wdt_of_data = {
285362
.cks_min = WDTCR_CKS_CLK_1,
286363
.cks_max = WDTCR_CKS_CLK_256,
@@ -292,6 +369,7 @@ static const struct rzv2h_of_data rzv2h_wdt_of_data = {
292369

293370
static const struct of_device_id rzv2h_wdt_ids[] = {
294371
{ .compatible = "renesas,r9a09g057-wdt", .data = &rzv2h_wdt_of_data },
372+
{ .compatible = "renesas,r9a09g077-wdt", .data = &rzt2h_wdt_of_data },
295373
{ /* sentinel */ }
296374
};
297375
MODULE_DEVICE_TABLE(of, rzv2h_wdt_ids);

0 commit comments

Comments
 (0)