1 // SPDX-License-Identifier: GPL-2.0
3 * Renesas RZ/G2L WDT Watchdog Driver
5 * Copyright (C) 2021 Renesas Electronics Corporation
7 #include <linux/bitops.h>
9 #include <linux/delay.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/pm_runtime.h>
16 #include <linux/reset.h>
17 #include <linux/units.h>
18 #include <linux/watchdog.h>
26 #define WDTCNT_WDTEN BIT(0)
27 #define WDTINT_INTDISP BIT(0)
28 #define PEEN_FORCE BIT(0)
30 #define WDT_DEFAULT_TIMEOUT 60U
32 /* Setting period time register only 12 bit set in WDTSET[31:20] */
33 #define WDTSET_COUNTER_MASK (0xFFF00000)
34 #define WDTSET_COUNTER_VAL(f) ((f) << 20)
36 #define F2CYCLE_NSEC(f) (1000000000 / (f))
38 #define RZV2M_A_NSEC 730
40 static bool nowayout
= WATCHDOG_NOWAYOUT
;
41 module_param(nowayout
, bool, 0);
42 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
43 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
50 struct rzg2l_wdt_priv
{
52 struct watchdog_device wdev
;
53 struct reset_control
*rstc
;
54 unsigned long osc_clk_rate
;
58 enum rz_wdt_type devtype
;
61 static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv
*priv
)
63 /* delay timer when change the setting register */
67 static u32
rzg2l_wdt_get_cycle_usec(unsigned long cycle
, u32 wdttime
)
69 u64 timer_cycle_us
= 1024 * 1024ULL * (wdttime
+ 1) * MICRO
;
71 return div64_ul(timer_cycle_us
, cycle
);
74 static void rzg2l_wdt_write(struct rzg2l_wdt_priv
*priv
, u32 val
, unsigned int reg
)
77 val
&= WDTSET_COUNTER_MASK
;
79 writel_relaxed(val
, priv
->base
+ reg
);
80 /* Registers other than the WDTINT is always synchronized with WDT_CLK */
82 rzg2l_wdt_wait_delay(priv
);
85 static void rzg2l_wdt_init_timeout(struct watchdog_device
*wdev
)
87 struct rzg2l_wdt_priv
*priv
= watchdog_get_drvdata(wdev
);
90 /* Clear Lapsed Time Register and clear Interrupt */
91 rzg2l_wdt_write(priv
, WDTINT_INTDISP
, WDTINT
);
92 /* 2 consecutive overflow cycle needed to trigger reset */
93 time_out
= (wdev
->timeout
* (MICRO
/ 2)) /
94 rzg2l_wdt_get_cycle_usec(priv
->osc_clk_rate
, 0);
95 rzg2l_wdt_write(priv
, WDTSET_COUNTER_VAL(time_out
), WDTSET
);
98 static int rzg2l_wdt_start(struct watchdog_device
*wdev
)
100 struct rzg2l_wdt_priv
*priv
= watchdog_get_drvdata(wdev
);
103 ret
= pm_runtime_resume_and_get(wdev
->parent
);
107 ret
= reset_control_deassert(priv
->rstc
);
109 pm_runtime_put(wdev
->parent
);
113 /* Initialize time out */
114 rzg2l_wdt_init_timeout(wdev
);
116 /* Initialize watchdog counter register */
117 rzg2l_wdt_write(priv
, 0, WDTTIM
);
119 /* Enable watchdog timer*/
120 rzg2l_wdt_write(priv
, WDTCNT_WDTEN
, WDTCNT
);
125 static int rzg2l_wdt_stop(struct watchdog_device
*wdev
)
127 struct rzg2l_wdt_priv
*priv
= watchdog_get_drvdata(wdev
);
130 ret
= reset_control_assert(priv
->rstc
);
134 ret
= pm_runtime_put(wdev
->parent
);
141 static int rzg2l_wdt_set_timeout(struct watchdog_device
*wdev
, unsigned int timeout
)
145 wdev
->timeout
= timeout
;
148 * If the watchdog is active, reset the module for updating the WDTSET
149 * register by calling rzg2l_wdt_stop() (which internally calls reset_control_reset()
150 * to reset the module) so that it is updated with new timeout values.
152 if (watchdog_active(wdev
)) {
153 ret
= rzg2l_wdt_stop(wdev
);
157 ret
= rzg2l_wdt_start(wdev
);
163 static int rzg2l_wdt_restart(struct watchdog_device
*wdev
,
164 unsigned long action
, void *data
)
166 struct rzg2l_wdt_priv
*priv
= watchdog_get_drvdata(wdev
);
169 clk_prepare_enable(priv
->pclk
);
170 clk_prepare_enable(priv
->osc_clk
);
172 if (priv
->devtype
== WDT_RZG2L
) {
173 ret
= reset_control_deassert(priv
->rstc
);
177 /* Generate Reset (WDTRSTB) Signal on parity error */
178 rzg2l_wdt_write(priv
, 0, PECR
);
180 /* Force parity error */
181 rzg2l_wdt_write(priv
, PEEN_FORCE
, PEEN
);
183 /* RZ/V2M doesn't have parity error registers */
184 ret
= reset_control_reset(priv
->rstc
);
190 /* Initialize time out */
191 rzg2l_wdt_init_timeout(wdev
);
193 /* Initialize watchdog counter register */
194 rzg2l_wdt_write(priv
, 0, WDTTIM
);
196 /* Enable watchdog timer*/
197 rzg2l_wdt_write(priv
, WDTCNT_WDTEN
, WDTCNT
);
199 /* Wait 2 consecutive overflow cycles for reset */
200 mdelay(DIV_ROUND_UP(2 * 0xFFFFF * 1000, priv
->osc_clk_rate
));
206 static const struct watchdog_info rzg2l_wdt_ident
= {
207 .options
= WDIOF_MAGICCLOSE
| WDIOF_KEEPALIVEPING
| WDIOF_SETTIMEOUT
,
208 .identity
= "Renesas RZ/G2L WDT Watchdog",
211 static int rzg2l_wdt_ping(struct watchdog_device
*wdev
)
213 struct rzg2l_wdt_priv
*priv
= watchdog_get_drvdata(wdev
);
215 rzg2l_wdt_write(priv
, WDTINT_INTDISP
, WDTINT
);
220 static const struct watchdog_ops rzg2l_wdt_ops
= {
221 .owner
= THIS_MODULE
,
222 .start
= rzg2l_wdt_start
,
223 .stop
= rzg2l_wdt_stop
,
224 .ping
= rzg2l_wdt_ping
,
225 .set_timeout
= rzg2l_wdt_set_timeout
,
226 .restart
= rzg2l_wdt_restart
,
229 static void rzg2l_wdt_pm_disable(void *data
)
231 struct watchdog_device
*wdev
= data
;
233 pm_runtime_disable(wdev
->parent
);
236 static int rzg2l_wdt_probe(struct platform_device
*pdev
)
238 struct device
*dev
= &pdev
->dev
;
239 struct rzg2l_wdt_priv
*priv
;
240 unsigned long pclk_rate
;
243 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
247 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
248 if (IS_ERR(priv
->base
))
249 return PTR_ERR(priv
->base
);
251 /* Get watchdog main clock */
252 priv
->osc_clk
= devm_clk_get(&pdev
->dev
, "oscclk");
253 if (IS_ERR(priv
->osc_clk
))
254 return dev_err_probe(&pdev
->dev
, PTR_ERR(priv
->osc_clk
), "no oscclk");
256 priv
->osc_clk_rate
= clk_get_rate(priv
->osc_clk
);
257 if (!priv
->osc_clk_rate
)
258 return dev_err_probe(&pdev
->dev
, -EINVAL
, "oscclk rate is 0");
260 /* Get Peripheral clock */
261 priv
->pclk
= devm_clk_get(&pdev
->dev
, "pclk");
262 if (IS_ERR(priv
->pclk
))
263 return dev_err_probe(&pdev
->dev
, PTR_ERR(priv
->pclk
), "no pclk");
265 pclk_rate
= clk_get_rate(priv
->pclk
);
267 return dev_err_probe(&pdev
->dev
, -EINVAL
, "pclk rate is 0");
269 priv
->delay
= F2CYCLE_NSEC(priv
->osc_clk_rate
) * 6 + F2CYCLE_NSEC(pclk_rate
) * 9;
271 priv
->rstc
= devm_reset_control_get_exclusive(&pdev
->dev
, NULL
);
272 if (IS_ERR(priv
->rstc
))
273 return dev_err_probe(&pdev
->dev
, PTR_ERR(priv
->rstc
),
274 "failed to get cpg reset");
276 priv
->devtype
= (uintptr_t)of_device_get_match_data(dev
);
278 pm_runtime_enable(&pdev
->dev
);
280 priv
->wdev
.info
= &rzg2l_wdt_ident
;
281 priv
->wdev
.ops
= &rzg2l_wdt_ops
;
282 priv
->wdev
.parent
= dev
;
283 priv
->wdev
.min_timeout
= 1;
284 priv
->wdev
.max_timeout
= rzg2l_wdt_get_cycle_usec(priv
->osc_clk_rate
, 0xfff) /
286 priv
->wdev
.timeout
= WDT_DEFAULT_TIMEOUT
;
288 watchdog_set_drvdata(&priv
->wdev
, priv
);
289 dev_set_drvdata(dev
, priv
);
290 ret
= devm_add_action_or_reset(&pdev
->dev
, rzg2l_wdt_pm_disable
, &priv
->wdev
);
294 watchdog_set_nowayout(&priv
->wdev
, nowayout
);
295 watchdog_stop_on_unregister(&priv
->wdev
);
297 ret
= watchdog_init_timeout(&priv
->wdev
, 0, dev
);
299 dev_warn(dev
, "Specified timeout invalid, using default");
301 return devm_watchdog_register_device(&pdev
->dev
, &priv
->wdev
);
304 static const struct of_device_id rzg2l_wdt_ids
[] = {
305 { .compatible
= "renesas,rzg2l-wdt", .data
= (void *)WDT_RZG2L
},
306 { .compatible
= "renesas,rzv2m-wdt", .data
= (void *)WDT_RZV2M
},
309 MODULE_DEVICE_TABLE(of
, rzg2l_wdt_ids
);
311 static int rzg2l_wdt_suspend_late(struct device
*dev
)
313 struct rzg2l_wdt_priv
*priv
= dev_get_drvdata(dev
);
315 if (!watchdog_active(&priv
->wdev
))
318 return rzg2l_wdt_stop(&priv
->wdev
);
321 static int rzg2l_wdt_resume_early(struct device
*dev
)
323 struct rzg2l_wdt_priv
*priv
= dev_get_drvdata(dev
);
325 if (!watchdog_active(&priv
->wdev
))
328 return rzg2l_wdt_start(&priv
->wdev
);
331 static const struct dev_pm_ops rzg2l_wdt_pm_ops
= {
332 LATE_SYSTEM_SLEEP_PM_OPS(rzg2l_wdt_suspend_late
, rzg2l_wdt_resume_early
)
335 static struct platform_driver rzg2l_wdt_driver
= {
338 .of_match_table
= rzg2l_wdt_ids
,
339 .pm
= &rzg2l_wdt_pm_ops
,
341 .probe
= rzg2l_wdt_probe
,
343 module_platform_driver(rzg2l_wdt_driver
);
345 MODULE_DESCRIPTION("Renesas RZ/G2L WDT Watchdog Driver");
346 MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
347 MODULE_LICENSE("GPL v2");