Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | // SPDX-License-Identifier: GPL-2.0+ #include <dm.h> #include <dm/device_compat.h> #include <wdt.h> #include <asm/gpio.h> #include <linux/delay.h> enum { HW_ALGO_TOGGLE, HW_ALGO_LEVEL, }; struct gpio_wdt_priv { struct gpio_desc gpio; unsigned int hw_algo; bool always_running; int state; }; static int gpio_wdt_reset(struct udevice *dev) { struct gpio_wdt_priv *priv = dev_get_priv(dev); switch (priv->hw_algo) { case HW_ALGO_TOGGLE: /* Toggle output pin */ priv->state = !priv->state; dm_gpio_set_value(&priv->gpio, priv->state); break; case HW_ALGO_LEVEL: /* Pulse */ dm_gpio_set_value(&priv->gpio, 1); __udelay(1); dm_gpio_set_value(&priv->gpio, 0); break; } return 0; } static int gpio_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct gpio_wdt_priv *priv = dev_get_priv(dev); if (priv->always_running) return 0; dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_OUT); gpio_wdt_reset(dev); return 0; } static int gpio_wdt_stop(struct udevice *dev) { struct gpio_wdt_priv *priv = dev_get_priv(dev); if (priv->always_running) return -EOPNOTSUPP; if (priv->hw_algo == HW_ALGO_TOGGLE) dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_IN); else dm_gpio_set_value(&priv->gpio, 1); return 0; } static int dm_probe(struct udevice *dev) { struct gpio_wdt_priv *priv = dev_get_priv(dev); const char *algo = dev_read_string(dev, "hw_algo"); int ret, flags; if (!algo) return -EINVAL; if (!strcmp(algo, "toggle")) priv->hw_algo = HW_ALGO_TOGGLE; else if (!strcmp(algo, "level")) priv->hw_algo = HW_ALGO_LEVEL; else return -EINVAL; priv->always_running = dev_read_bool(dev, "always-running"); flags = priv->always_running || priv->hw_algo == HW_ALGO_LEVEL ? GPIOD_IS_OUT : GPIOD_IS_IN; ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, flags); if (ret < 0) { dev_err(dev, "Request for wdt gpio failed: %d\n", ret); return ret; } if (priv->always_running) ret = gpio_wdt_reset(dev); return ret; } static const struct wdt_ops gpio_wdt_ops = { .start = gpio_wdt_start, .stop = gpio_wdt_stop, .reset = gpio_wdt_reset, }; static const struct udevice_id gpio_wdt_ids[] = { { .compatible = "linux,wdt-gpio" }, {} }; U_BOOT_DRIVER(wdt_gpio) = { .name = "wdt_gpio", .id = UCLASS_WDT, .of_match = gpio_wdt_ids, .ops = &gpio_wdt_ops, .probe = dm_probe, .priv_auto = sizeof(struct gpio_wdt_priv), }; |