watchdog: add pulse support to gpio watchdog driver
[platform/kernel/u-boot.git] / drivers / watchdog / gpio_wdt.c
1 // SPDX-License-Identifier: GPL-2.0+
2
3 #include <dm.h>
4 #include <dm/device_compat.h>
5 #include <wdt.h>
6 #include <asm/gpio.h>
7 #include <linux/delay.h>
8
9 enum {
10         HW_ALGO_TOGGLE,
11         HW_ALGO_LEVEL,
12 };
13
14 struct gpio_wdt_priv {
15         struct          gpio_desc gpio;
16         unsigned int    hw_algo;
17         bool            always_running;
18         int             state;
19 };
20
21 static int gpio_wdt_reset(struct udevice *dev)
22 {
23         struct gpio_wdt_priv *priv = dev_get_priv(dev);
24
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;
39 }
40
41 static int gpio_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
42 {
43         struct gpio_wdt_priv *priv = dev_get_priv(dev);
44
45         if (priv->always_running)
46                 return 0;
47
48         return -ENOSYS;
49 }
50
51 static int dm_probe(struct udevice *dev)
52 {
53         struct gpio_wdt_priv *priv = dev_get_priv(dev);
54         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;
65
66         priv->always_running = dev_read_bool(dev, "always-running");
67         ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
68         if (ret < 0) {
69                 dev_err(dev, "Request for wdt gpio failed: %d\n", ret);
70                 return ret;
71         }
72
73         if (priv->always_running)
74                 ret = gpio_wdt_reset(dev);
75
76         return ret;
77 }
78
79 static const struct wdt_ops gpio_wdt_ops = {
80         .start = gpio_wdt_start,
81         .reset = gpio_wdt_reset,
82 };
83
84 static const struct udevice_id gpio_wdt_ids[] = {
85         { .compatible = "linux,wdt-gpio" },
86         {}
87 };
88
89 U_BOOT_DRIVER(wdt_gpio) = {
90         .name = "wdt_gpio",
91         .id = UCLASS_WDT,
92         .of_match = gpio_wdt_ids,
93         .ops = &gpio_wdt_ops,
94         .probe  = dm_probe,
95         .priv_auto = sizeof(struct gpio_wdt_priv),
96 };