watchdog: add pulse support to gpio watchdog driver

A common external watchdog circuit is kept alive by triggering a short
pulse on the reset pin. This patch adds support for this use case, while
making the algorithm configurable in the devicetree.

The "linux,wdt-gpio" driver being modified is based off the equivalent
driver in the Linux kernel, which provides support for this algorithm.
This patch brings parity to this driver, and is kept aligned with
the functionality and devicetree configuration in the kernel.

It should be noted that this adds a required property named 'hw_algo'
to the devicetree binding, following suit with the kernel. I'm happy to
make this backward-compatible if preferred.

Signed-off-by: Paul Doelle <paaull.git@gmail.com>
Reviewed-by: Stefan Roese <sr@denx.de>
diff --git a/test/dm/wdt.c b/test/dm/wdt.c
index ee615f0..535f00a 100644
--- a/test/dm/wdt.c
+++ b/test/dm/wdt.c
@@ -44,20 +44,20 @@
 }
 DM_TEST(dm_test_wdt_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
-static int dm_test_wdt_gpio(struct unit_test_state *uts)
+static int dm_test_wdt_gpio_toggle(struct unit_test_state *uts)
 {
 	/*
 	 * The sandbox wdt gpio is "connected" to gpio bank a, offset
 	 * 7. Use the sandbox back door to verify that the gpio-wdt
-	 * driver behaves as expected.
+	 * driver behaves as expected when using the 'toggle' algorithm.
 	 */
 	struct udevice *wdt, *gpio;
 	const u64 timeout = 42;
 	const int offset = 7;
 	int val;
 
-	ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
-						DM_DRIVER_GET(wdt_gpio), &wdt));
+	ut_assertok(uclass_get_device_by_name(UCLASS_WDT,
+					      "wdt-gpio-toggle", &wdt));
 	ut_assertnonnull(wdt);
 
 	ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
@@ -74,7 +74,39 @@
 
 	return 0;
 }
-DM_TEST(dm_test_wdt_gpio, UT_TESTF_SCAN_FDT);
+DM_TEST(dm_test_wdt_gpio_toggle, UT_TESTF_SCAN_FDT);
+
+static int dm_test_wdt_gpio_level(struct unit_test_state *uts)
+{
+	/*
+	 * The sandbox wdt gpio is "connected" to gpio bank a, offset
+	 * 7. Use the sandbox back door to verify that the gpio-wdt
+	 * driver behaves as expected when using the 'level' algorithm.
+	 */
+	struct udevice *wdt, *gpio;
+	const u64 timeout = 42;
+	const int offset = 7;
+	int val;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_WDT,
+					      "wdt-gpio-level", &wdt));
+	ut_assertnonnull(wdt);
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
+	ut_assertnonnull(gpio);
+	ut_assertok(wdt_start(wdt, timeout, 0));
+
+	val = sandbox_gpio_get_value(gpio, offset);
+	ut_assertok(wdt_reset(wdt));
+	ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
+	ut_assertok(wdt_reset(wdt));
+	ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
+
+	ut_asserteq(-ENOSYS, wdt_stop(wdt));
+
+	return 0;
+}
+DM_TEST(dm_test_wdt_gpio_level, UT_TESTF_SCAN_FDT);
 
 static int dm_test_wdt_watchdog_reset(struct unit_test_state *uts)
 {
@@ -86,8 +118,8 @@
 	uint reset_count;
 	int val;
 
-	ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
-						DM_DRIVER_GET(wdt_gpio), &gpio_wdt));
+	ut_assertok(uclass_get_device_by_name(UCLASS_WDT,
+					      "wdt-gpio-toggle", &gpio_wdt));
 	ut_assertnonnull(gpio_wdt);
 	ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
 						DM_DRIVER_GET(wdt_sandbox), &sandbox_wdt));