watchdog: designware: Optionally fetch clock and reset from DT

Add optional support for fetching watchdog clock rate from DT
and ungating reset via reset framework. This is optional as not
all platforms using DW WDT support the clock and reset frameworks
yet.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Chin Liang See <chin.liang.see@intel.com>
Cc: Dalon Westergreen <dwesterg@gmail.com>
Cc: Dinh Nguyen <dinguyen@kernel.org>
Cc: Jagan Teki <jagan@amarulasolutions.com>
Cc: Ley Foon Tan <ley.foon.tan@intel.com>
Cc: Philipp Tomisch <philipp.tomisch@theobroma-systems.com>
Cc: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
Cc: Tien Fong Chee <tien.fong.chee@intel.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
Tested-by: Jagan Teki <jagan@amarulasolutions.com> # roc-rk3399-pc
diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c
index a7b7359..1024a04 100644
--- a/drivers/watchdog/designware_wdt.c
+++ b/drivers/watchdog/designware_wdt.c
@@ -3,8 +3,10 @@
  * Copyright (C) 2013 Altera Corporation <www.altera.com>
  */
 
+#include <clk.h>
 #include <common.h>
 #include <dm.h>
+#include <reset.h>
 #include <wdt.h>
 #include <asm/io.h>
 #include <asm/utils.h>
@@ -15,11 +17,11 @@
 
 #define DW_WDT_CR_EN_OFFSET	0x00
 #define DW_WDT_CR_RMOD_OFFSET	0x01
-#define DW_WDT_CR_RMOD_VAL	0x00
 #define DW_WDT_CRR_RESTART_VAL	0x76
 
 struct designware_wdt_priv {
 	void __iomem	*base;
+	unsigned int	clk_khz;
 };
 
 /*
@@ -42,9 +44,7 @@
 
 static void designware_wdt_enable(void __iomem *base)
 {
-	writel((DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET) |
-		BIT(DW_WDT_CR_EN_OFFSET),
-		base + DW_WDT_CR);
+	writel(BIT(DW_WDT_CR_EN_OFFSET), base + DW_WDT_CR);
 }
 
 static unsigned int designware_wdt_is_enabled(void __iomem *base)
@@ -93,8 +93,7 @@
 	struct designware_wdt_priv *priv = dev_get_priv(dev);
 
 	designware_wdt_reset(dev);
-	writel(DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET,
-		priv->base + DW_WDT_CR);
+	writel(0, priv->base + DW_WDT_CR);
 
 	return 0;
 }
@@ -106,7 +105,7 @@
 	designware_wdt_stop(dev);
 
 	/* set timer in miliseconds */
-	designware_wdt_settimeout(priv->base, CONFIG_DW_WDT_CLOCK_KHZ, timeout);
+	designware_wdt_settimeout(priv->base, priv->clk_khz, timeout);
 
 	designware_wdt_enable(priv->base);
 
@@ -117,11 +116,38 @@
 static int designware_wdt_probe(struct udevice *dev)
 {
 	struct designware_wdt_priv *priv = dev_get_priv(dev);
+	__maybe_unused int ret;
 
 	priv->base = dev_remap_addr(dev);
 	if (!priv->base)
 		return -EINVAL;
 
+#if CONFIG_IS_ENABLED(CLK)
+	struct clk clk;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret)
+		return ret;
+
+	priv->clk_khz = clk_get_rate(&clk);
+	if (!priv->clk_khz)
+		return -EINVAL;
+#else
+	priv->clk_khz = CONFIG_DW_WDT_CLOCK_KHZ;
+#endif
+
+#if CONFIG_IS_ENABLED(DM_RESET)
+	struct reset_ctl_bulk resets;
+
+	ret = reset_get_bulk(dev, &resets);
+	if (ret)
+		return ret;
+
+	ret = reset_deassert_bulk(&resets);
+	if (ret)
+		return ret;
+#endif
+
 	/* reset to disable the watchdog */
 	return designware_wdt_stop(dev);
 }