watchdog: imx: Add DM support

Add DM and DT probing support to iMX watchdog driver. This should
allow boards to move over to this driver, enable SYSRESET_WATCHDOG
to handle cpu_reset() if required.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Peng Fan <Peng.Fan@freescale.com>
Cc: Stefano Babic <sbabic@denx.de>
Tested-by: Heiko Schocher <hs@denx.de>
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index de9bd87..ccda432 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -28,7 +28,7 @@
 
 config IMX_WATCHDOG
 	bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
-	select HW_WATCHDOG
+	select HW_WATCHDOG if !WDT
 	help
 	   Select this to enable the IMX and LSCH2 of Layerscape watchdog
 	   driver.
diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
index 14cc618..53a3e9f 100644
--- a/drivers/watchdog/imx_watchdog.c
+++ b/drivers/watchdog/imx_watchdog.c
@@ -5,7 +5,9 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/io.h>
+#include <wdt.h>
 #include <watchdog.h>
 #include <asm/arch/imx-regs.h>
 #ifdef CONFIG_FSL_LSCH2
@@ -13,20 +15,40 @@
 #endif
 #include <fsl_wdog.h>
 
-#ifdef CONFIG_IMX_WATCHDOG
-void hw_watchdog_reset(void)
+static void imx_watchdog_expire_now(struct watchdog_regs *wdog)
 {
-#ifndef CONFIG_WATCHDOG_RESET_DISABLE
+	clrsetbits_le16(&wdog->wcr, WCR_WT_MSK, WCR_WDE);
+
+	writew(0x5555, &wdog->wsr);
+	writew(0xaaaa, &wdog->wsr);	/* load minimum 1/2 second timeout */
+	while (1) {
+		/*
+		 * spin for .5 seconds before reset
+		 */
+	}
+}
+
+#if !defined(CONFIG_IMX_WATCHDOG) || \
+    (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
+void __attribute__((weak)) reset_cpu(ulong addr)
+{
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
+	imx_watchdog_expire_now(wdog);
+}
+#endif
+
+#if defined(CONFIG_IMX_WATCHDOG)
+static void imx_watchdog_reset(struct watchdog_regs *wdog)
+{
+#ifndef CONFIG_WATCHDOG_RESET_DISABLE
 	writew(0x5555, &wdog->wsr);
 	writew(0xaaaa, &wdog->wsr);
 #endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
 }
 
-void hw_watchdog_init(void)
+static void imx_watchdog_init(struct watchdog_regs *wdog)
 {
-	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 	u16 timeout;
 
 	/*
@@ -44,21 +66,86 @@
 	writew(WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_WDT | WCR_SRS |
 		WCR_WDA | SET_WCR_WT(timeout), &wdog->wcr);
 #endif /* CONFIG_FSL_LSCH2*/
-	hw_watchdog_reset();
+	imx_watchdog_reset(wdog);
 }
-#endif
 
-void __attribute__((weak)) reset_cpu(ulong addr)
+#if !CONFIG_IS_ENABLED(WDT)
+void hw_watchdog_reset(void)
 {
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
-	clrsetbits_le16(&wdog->wcr, WCR_WT_MSK, WCR_WDE);
-
-	writew(0x5555, &wdog->wsr);
-	writew(0xaaaa, &wdog->wsr);	/* load minimum 1/2 second timeout */
-	while (1) {
-		/*
-		 * spin for .5 seconds before reset
-		 */
-	}
+	imx_watchdog_reset(wdog);
 }
+
+void hw_watchdog_init(void)
+{
+	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
+
+	imx_watchdog_init(wdog);
+}
+#else
+struct imx_wdt_priv {
+	void __iomem *base;
+};
+
+static int imx_wdt_reset(struct udevice *dev)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	imx_watchdog_reset(priv->base);
+
+	return 0;
+}
+
+static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	imx_watchdog_expire_now(priv->base);
+	hang();
+
+	return 0;
+}
+
+static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	imx_watchdog_init(priv->base);
+
+	return 0;
+}
+
+static int imx_wdt_probe(struct udevice *dev)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -ENOENT;
+
+	return 0;
+}
+
+static const struct wdt_ops imx_wdt_ops = {
+	.start		= imx_wdt_start,
+	.reset		= imx_wdt_reset,
+	.expire_now	= imx_wdt_expire_now,
+};
+
+static const struct udevice_id imx_wdt_ids[] = {
+	{ .compatible = "fsl,imx21-wdt" },
+	{}
+};
+
+U_BOOT_DRIVER(imx_wdt) = {
+	.name		= "imx_wdt",
+	.id		= UCLASS_WDT,
+	.of_match	= imx_wdt_ids,
+	.probe		= imx_wdt_probe,
+	.ops		= &imx_wdt_ops,
+	.priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
+	.flags		= DM_FLAG_PRE_RELOC,
+};
+#endif
+#endif