blob: e889861e917b1ad96f416f85cc257e628964a346 [file] [log] [blame]
Rasmus Villemoes08667602021-08-19 11:57:04 +02001// 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>
Paul Doelle709f0372022-07-04 09:00:25 +00007#include <linux/delay.h>
8
9enum {
10 HW_ALGO_TOGGLE,
11 HW_ALGO_LEVEL,
12};
Rasmus Villemoes08667602021-08-19 11:57:04 +020013
14struct gpio_wdt_priv {
Paul Doelle709f0372022-07-04 09:00:25 +000015 struct gpio_desc gpio;
16 unsigned int hw_algo;
17 bool always_running;
18 int state;
Rasmus Villemoes08667602021-08-19 11:57:04 +020019};
20
21static int gpio_wdt_reset(struct udevice *dev)
22{
23 struct gpio_wdt_priv *priv = dev_get_priv(dev);
24
Paul Doelle709f0372022-07-04 09:00:25 +000025 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);
Rasmus Villemoes21df2512022-09-27 09:45:44 +020034 __udelay(1);
Paul Doelle709f0372022-07-04 09:00:25 +000035 dm_gpio_set_value(&priv->gpio, 0);
36 break;
37 }
38 return 0;
Rasmus Villemoes08667602021-08-19 11:57:04 +020039}
40
41static 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
Rasmus Villemoes776442e2024-10-02 21:23:23 +020048 dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_OUT);
49 gpio_wdt_reset(dev);
50
51 return 0;
52}
53
54static int gpio_wdt_stop(struct udevice *dev)
55{
56 struct gpio_wdt_priv *priv = dev_get_priv(dev);
57
58 if (priv->always_running)
59 return -EOPNOTSUPP;
60
61 if (priv->hw_algo == HW_ALGO_TOGGLE)
62 dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_IN);
63 else
64 dm_gpio_set_value(&priv->gpio, 1);
65
66 return 0;
Rasmus Villemoes08667602021-08-19 11:57:04 +020067}
68
69static int dm_probe(struct udevice *dev)
70{
71 struct gpio_wdt_priv *priv = dev_get_priv(dev);
Paul Doelle709f0372022-07-04 09:00:25 +000072 const char *algo = dev_read_string(dev, "hw_algo");
Rasmus Villemoes776442e2024-10-02 21:23:23 +020073 int ret, flags;
Paul Doelle709f0372022-07-04 09:00:25 +000074
75 if (!algo)
76 return -EINVAL;
77 if (!strcmp(algo, "toggle"))
78 priv->hw_algo = HW_ALGO_TOGGLE;
79 else if (!strcmp(algo, "level"))
80 priv->hw_algo = HW_ALGO_LEVEL;
81 else
82 return -EINVAL;
Rasmus Villemoes08667602021-08-19 11:57:04 +020083
84 priv->always_running = dev_read_bool(dev, "always-running");
Rasmus Villemoes776442e2024-10-02 21:23:23 +020085 flags = priv->always_running || priv->hw_algo == HW_ALGO_LEVEL ?
86 GPIOD_IS_OUT : GPIOD_IS_IN;
87 ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, flags);
Rasmus Villemoes08667602021-08-19 11:57:04 +020088 if (ret < 0) {
89 dev_err(dev, "Request for wdt gpio failed: %d\n", ret);
90 return ret;
91 }
92
93 if (priv->always_running)
94 ret = gpio_wdt_reset(dev);
95
96 return ret;
97}
98
99static const struct wdt_ops gpio_wdt_ops = {
100 .start = gpio_wdt_start,
Rasmus Villemoes776442e2024-10-02 21:23:23 +0200101 .stop = gpio_wdt_stop,
Rasmus Villemoes08667602021-08-19 11:57:04 +0200102 .reset = gpio_wdt_reset,
103};
104
105static const struct udevice_id gpio_wdt_ids[] = {
106 { .compatible = "linux,wdt-gpio" },
107 {}
108};
109
110U_BOOT_DRIVER(wdt_gpio) = {
111 .name = "wdt_gpio",
112 .id = UCLASS_WDT,
113 .of_match = gpio_wdt_ids,
114 .ops = &gpio_wdt_ops,
115 .probe = dm_probe,
116 .priv_auto = sizeof(struct gpio_wdt_priv),
117};