• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revision1fc45d6483d77b9fbe84e546f4e6afe665ba827a (tree)
Time2022-07-21 15:09:06
AuthorPaul Doelle <paaull.git@gmai...>
CommiterStefan Roese

Log Message

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>

Change Summary

Incremental Difference

--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -850,10 +850,19 @@
850850 };
851851 };
852852
853- gpio-wdt {
853+ wdt-gpio-toggle {
854854 gpios = <&gpio_a 7 0>;
855855 compatible = "linux,wdt-gpio";
856856 hw_margin_ms = <100>;
857+ hw_algo = "toggle";
858+ always-running;
859+ };
860+
861+ wdt-gpio-level {
862+ gpios = <&gpio_a 7 0>;
863+ compatible = "linux,wdt-gpio";
864+ hw_margin_ms = <100>;
865+ hw_algo = "level";
857866 always-running;
858867 };
859868
--- a/doc/device-tree-bindings/watchdog/gpio-wdt.txt
+++ b/doc/device-tree-bindings/watchdog/gpio-wdt.txt
@@ -5,7 +5,12 @@ Describes a simple watchdog timer which is reset by toggling a gpio.
55 Required properties:
66
77 - compatible: Must be "linux,wdt-gpio".
8-- gpios: gpio to toggle when wdt driver reset method is called.
8+- gpios: From common gpio binding; gpio connection to WDT reset pin.
9+- hw_algo: The algorithm used by the driver. Should be one of the
10+ following values:
11+ - toggle: Toggle from high-to-low or low-to-high when resetting the watchdog.
12+ - level: Maintain a constant high/low level, and trigger a short pulse when
13+ resetting the watchdog. Active level is determined by the GPIO flags.
914 - always-running: Boolean property indicating that the watchdog cannot
1015 be disabled. At present, U-Boot only supports this kind of GPIO
1116 watchdog.
@@ -15,5 +20,6 @@ Example:
1520 gpio-wdt {
1621 gpios = <&gpio0 1 0>;
1722 compatible = "linux,wdt-gpio";
23+ hw_algo = "toggle";
1824 always-running;
1925 };
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -4,20 +4,38 @@
44 #include <dm/device_compat.h>
55 #include <wdt.h>
66 #include <asm/gpio.h>
7+#include <linux/delay.h>
8+
9+enum {
10+ HW_ALGO_TOGGLE,
11+ HW_ALGO_LEVEL,
12+};
713
814 struct gpio_wdt_priv {
9- struct gpio_desc gpio;
10- bool always_running;
11- int state;
15+ struct gpio_desc gpio;
16+ unsigned int hw_algo;
17+ bool always_running;
18+ int state;
1219 };
1320
1421 static int gpio_wdt_reset(struct udevice *dev)
1522 {
1623 struct gpio_wdt_priv *priv = dev_get_priv(dev);
1724
18- priv->state = !priv->state;
19-
20- return dm_gpio_set_value(&priv->gpio, priv->state);
25+ switch (priv->hw_algo) {
26+ case HW_ALGO_TOGGLE:
27+ /* Toggle output pin */
28+ priv->state = !priv->state;
29+ dm_gpio_set_value(&priv->gpio, priv->state);
30+ break;
31+ case HW_ALGO_LEVEL:
32+ /* Pulse */
33+ dm_gpio_set_value(&priv->gpio, 1);
34+ udelay(1);
35+ dm_gpio_set_value(&priv->gpio, 0);
36+ break;
37+ }
38+ return 0;
2139 }
2240
2341 static int gpio_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
@@ -34,6 +52,16 @@ static int dm_probe(struct udevice *dev)
3452 {
3553 struct gpio_wdt_priv *priv = dev_get_priv(dev);
3654 int ret;
55+ const char *algo = dev_read_string(dev, "hw_algo");
56+
57+ if (!algo)
58+ return -EINVAL;
59+ if (!strcmp(algo, "toggle"))
60+ priv->hw_algo = HW_ALGO_TOGGLE;
61+ else if (!strcmp(algo, "level"))
62+ priv->hw_algo = HW_ALGO_LEVEL;
63+ else
64+ return -EINVAL;
3765
3866 priv->always_running = dev_read_bool(dev, "always-running");
3967 ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
--- a/test/dm/wdt.c
+++ b/test/dm/wdt.c
@@ -44,20 +44,20 @@ static int dm_test_wdt_base(struct unit_test_state *uts)
4444 }
4545 DM_TEST(dm_test_wdt_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
4646
47-static int dm_test_wdt_gpio(struct unit_test_state *uts)
47+static int dm_test_wdt_gpio_toggle(struct unit_test_state *uts)
4848 {
4949 /*
5050 * The sandbox wdt gpio is "connected" to gpio bank a, offset
5151 * 7. Use the sandbox back door to verify that the gpio-wdt
52- * driver behaves as expected.
52+ * driver behaves as expected when using the 'toggle' algorithm.
5353 */
5454 struct udevice *wdt, *gpio;
5555 const u64 timeout = 42;
5656 const int offset = 7;
5757 int val;
5858
59- ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
60- DM_DRIVER_GET(wdt_gpio), &wdt));
59+ ut_assertok(uclass_get_device_by_name(UCLASS_WDT,
60+ "wdt-gpio-toggle", &wdt));
6161 ut_assertnonnull(wdt);
6262
6363 ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
@@ -74,7 +74,39 @@ static int dm_test_wdt_gpio(struct unit_test_state *uts)
7474
7575 return 0;
7676 }
77-DM_TEST(dm_test_wdt_gpio, UT_TESTF_SCAN_FDT);
77+DM_TEST(dm_test_wdt_gpio_toggle, UT_TESTF_SCAN_FDT);
78+
79+static int dm_test_wdt_gpio_level(struct unit_test_state *uts)
80+{
81+ /*
82+ * The sandbox wdt gpio is "connected" to gpio bank a, offset
83+ * 7. Use the sandbox back door to verify that the gpio-wdt
84+ * driver behaves as expected when using the 'level' algorithm.
85+ */
86+ struct udevice *wdt, *gpio;
87+ const u64 timeout = 42;
88+ const int offset = 7;
89+ int val;
90+
91+ ut_assertok(uclass_get_device_by_name(UCLASS_WDT,
92+ "wdt-gpio-level", &wdt));
93+ ut_assertnonnull(wdt);
94+
95+ ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
96+ ut_assertnonnull(gpio);
97+ ut_assertok(wdt_start(wdt, timeout, 0));
98+
99+ val = sandbox_gpio_get_value(gpio, offset);
100+ ut_assertok(wdt_reset(wdt));
101+ ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
102+ ut_assertok(wdt_reset(wdt));
103+ ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
104+
105+ ut_asserteq(-ENOSYS, wdt_stop(wdt));
106+
107+ return 0;
108+}
109+DM_TEST(dm_test_wdt_gpio_level, UT_TESTF_SCAN_FDT);
78110
79111 static int dm_test_wdt_watchdog_reset(struct unit_test_state *uts)
80112 {
@@ -86,8 +118,8 @@ static int dm_test_wdt_watchdog_reset(struct unit_test_state *uts)
86118 uint reset_count;
87119 int val;
88120
89- ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
90- DM_DRIVER_GET(wdt_gpio), &gpio_wdt));
121+ ut_assertok(uclass_get_device_by_name(UCLASS_WDT,
122+ "wdt-gpio-toggle", &gpio_wdt));
91123 ut_assertnonnull(gpio_wdt);
92124 ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
93125 DM_DRIVER_GET(wdt_sandbox), &sandbox_wdt));