[PATCH v3 6/8] watchdog: rzv2h: Add syscon support for WDTDCR
Prabhakar <[email protected]> Thu, 16 Jul 2026 13:34:32 +0100
| Newsgroups | org.kernel.vger.linux-watchdog,org.kernel.vger.linux-clk,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-renesas-soc |
|---|---|
| Message-ID | <[email protected]> |
From: Lad Prabhakar <[email protected]> On RZ/T2H and RZ/N2H SoCs, the WDTDCR (WDT Debug Control Register) resides in the second register region of the CPG/MSSR block. Since this multi-function block is shared with other peripherals, it is exposed via a syscon regmap interface. Look up the SYSC regmap using the optional "renesas,sysc" property and derive the WDTDCR offset from the watchdog instance index. Retain the existing MMIO-based access method when the "renesas,sysc" property is absent to preserve compatibility with existing DT's. Signed-off-by: Lad Prabhakar <[email protected]> --- v2->v3: - Made use of the new "renesas,sysc" phandle-array property to access the WDTDCR register via the CPG/MSSR syscon node. - Updated commit message v1->v2: - No change. --- drivers/watchdog/Kconfig | 1 + drivers/watchdog/rzv2h_wdt.c | 56 +++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9f013d774897..9267fd74bfb2 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1036,6 +1036,7 @@ config RENESAS_RZV2HWDT depends on ARCH_RENESAS || COMPILE_TEST depends on PM || COMPILE_TEST select WATCHDOG_CORE + select MFD_SYSCON help This driver adds watchdog support for the integrated watchdogs in the Renesas RZ/{G3E,V2H(P)} SoCs. These watchdogs can be used to reset a diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index 3c8739902ec4..58daa6b6e3e0 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -8,6 +8,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -44,6 +45,11 @@ #define WDT_DEFAULT_TIMEOUT 60U +#define RZT2H_WDT_MAX_INSTANCES 6 + +#define RZT2H_SYS_BLOCK1(n) (BIT(16) | (0x5100 + (n) * 4)) +#define RZT2H_WDTDCR_OFFSET(n) RZT2H_SYS_BLOCK1(n) + static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" @@ -64,14 +70,19 @@ struct rzv2h_of_data { bool wdtdcr; }; +struct rzv2h_sysc_wdtdcr { + struct regmap *regmap; + unsigned int offset; +}; + struct rzv2h_wdt_priv { void __iomem *base; - struct regmap *wdtdcr_regmap; struct clk *pclk; struct clk *oscclk; struct reset_control *rstc; struct watchdog_device wdev; const struct rzv2h_of_data *of_data; + struct rzv2h_sysc_wdtdcr sysc; }; static int rzv2h_wdt_ping(struct watchdog_device *wdev) @@ -90,12 +101,16 @@ static int rzv2h_wdt_ping(struct watchdog_device *wdev) static int rzt2h_wdt_wdtdcr_count_stop(struct rzv2h_wdt_priv *priv) { - return regmap_set_bits(priv->wdtdcr_regmap, WDTDCR, WDTDCR_WDTSTOPCTRL); + struct rzv2h_sysc_wdtdcr *sysc = &priv->sysc; + + return regmap_set_bits(sysc->regmap, sysc->offset, WDTDCR_WDTSTOPCTRL); } static int rzt2h_wdt_wdtdcr_count_start(struct rzv2h_wdt_priv *priv) { - return regmap_clear_bits(priv->wdtdcr_regmap, WDTDCR, WDTDCR_WDTSTOPCTRL); + struct rzv2h_sysc_wdtdcr *sysc = &priv->sysc; + + return regmap_clear_bits(sysc->regmap, sysc->offset, WDTDCR_WDTSTOPCTRL); } static void rzv2h_wdt_setup(struct watchdog_device *wdev, u16 wdtcr) @@ -281,17 +296,36 @@ static const struct regmap_config rzv2h_wdtdcr_regmap_config = { static int rzt2h_wdt_wdtdcr_init(struct platform_device *pdev, struct rzv2h_wdt_priv *priv) { - void __iomem *wdtdcr; + struct device_node *np = pdev->dev.of_node; + bool syscon_present = of_property_present(np, "renesas,sysc"); + struct rzv2h_sysc_wdtdcr *sysc = &priv->sysc; int ret; - wdtdcr = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(wdtdcr)) - return PTR_ERR(wdtdcr); + if (syscon_present) { + unsigned int wdt_index; - priv->wdtdcr_regmap = devm_regmap_init_mmio(&pdev->dev, wdtdcr, - &rzv2h_wdtdcr_regmap_config); - if (IS_ERR(priv->wdtdcr_regmap)) - return PTR_ERR(priv->wdtdcr_regmap); + sysc->regmap = syscon_regmap_lookup_by_phandle_args(np, "renesas,sysc", + 1, &wdt_index); + if (IS_ERR(sysc->regmap)) + return PTR_ERR(sysc->regmap); + + if (wdt_index >= RZT2H_WDT_MAX_INSTANCES) + return -EINVAL; + + sysc->offset = RZT2H_WDTDCR_OFFSET(wdt_index); + } else { + void __iomem *wdtdcr; + + wdtdcr = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(wdtdcr)) + return PTR_ERR(wdtdcr); + + sysc->regmap = devm_regmap_init_mmio(&pdev->dev, wdtdcr, + &rzv2h_wdtdcr_regmap_config); + if (IS_ERR(sysc->regmap)) + return PTR_ERR(sysc->regmap); + sysc->offset = WDTDCR; + } ret = pm_runtime_resume_and_get(&pdev->dev); if (ret) -- 2.54.0