1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Driver for watchdog device controlled through GPIO-line 4 * 5 * Author: 2013, Alexander Shiyan <shc_work@mail.ru> 6 */ 7 8 #include <linux/err.h> 9 #include <linux/delay.h> 10 #include <linux/module.h> 11 #include <linux/gpio/consumer.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 #include <linux/watchdog.h> 15 16 #define SOFT_TIMEOUT_MIN 1 17 #define SOFT_TIMEOUT_DEF 60 18 19 enum { 20 HW_ALGO_TOGGLE, 21 HW_ALGO_LEVEL, 22 }; 23 24 struct gpio_wdt_priv { 25 struct gpio_desc *gpiod; 26 bool state; 27 bool always_running; 28 unsigned int hw_algo; 29 struct watchdog_device wdd; 30 }; 31 32 static void gpio_wdt_disable(struct gpio_wdt_priv *priv) 33 { 34 /* Eternal ping */ 35 gpiod_set_value_cansleep(priv->gpiod, 1); 36 37 /* Put GPIO back to tristate */ 38 if (priv->hw_algo == HW_ALGO_TOGGLE) 39 gpiod_direction_input(priv->gpiod); 40 } 41 42 static int gpio_wdt_ping(struct watchdog_device *wdd) 43 { 44 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); 45 46 switch (priv->hw_algo) { 47 case HW_ALGO_TOGGLE: 48 /* Toggle output pin */ 49 priv->state = !priv->state; 50 gpiod_set_value_cansleep(priv->gpiod, priv->state); 51 break; 52 case HW_ALGO_LEVEL: 53 /* Pulse */ 54 gpiod_set_value_cansleep(priv->gpiod, 1); 55 udelay(1); 56 gpiod_set_value_cansleep(priv->gpiod, 0); 57 break; 58 } 59 return 0; 60 } 61 62 static int gpio_wdt_start(struct watchdog_device *wdd) 63 { 64 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); 65 66 priv->state = 0; 67 gpiod_direction_output(priv->gpiod, priv->state); 68 69 set_bit(WDOG_HW_RUNNING, &wdd->status); 70 71 return gpio_wdt_ping(wdd); 72 } 73 74 static int gpio_wdt_stop(struct watchdog_device *wdd) 75 { 76 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); 77 78 if (!priv->always_running) { 79 gpio_wdt_disable(priv); 80 } else { 81 set_bit(WDOG_HW_RUNNING, &wdd->status); 82 } 83 84 return 0; 85 } 86 87 static const struct watchdog_info gpio_wdt_ident = { 88 .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | 89 WDIOF_SETTIMEOUT, 90 .identity = "GPIO Watchdog", 91 }; 92 93 static const struct watchdog_ops gpio_wdt_ops = { 94 .owner = THIS_MODULE, 95 .start = gpio_wdt_start, 96 .stop = gpio_wdt_stop, 97 .ping = gpio_wdt_ping, 98 }; 99 100 static int gpio_wdt_probe(struct platform_device *pdev) 101 { 102 struct device *dev = &pdev->dev; 103 struct device_node *np = dev->of_node; 104 struct gpio_wdt_priv *priv; 105 enum gpiod_flags gflags; 106 unsigned int hw_margin; 107 const char *algo; 108 int ret; 109 110 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 111 if (!priv) 112 return -ENOMEM; 113 114 platform_set_drvdata(pdev, priv); 115 116 ret = of_property_read_string(np, "hw_algo", &algo); 117 if (ret) 118 return ret; 119 if (!strcmp(algo, "toggle")) { 120 priv->hw_algo = HW_ALGO_TOGGLE; 121 gflags = GPIOD_IN; 122 } else if (!strcmp(algo, "level")) { 123 priv->hw_algo = HW_ALGO_LEVEL; 124 gflags = GPIOD_OUT_LOW; 125 } else { 126 return -EINVAL; 127 } 128 129 priv->gpiod = devm_gpiod_get(dev, NULL, gflags); 130 if (IS_ERR(priv->gpiod)) 131 return PTR_ERR(priv->gpiod); 132 133 ret = of_property_read_u32(np, 134 "hw_margin_ms", &hw_margin); 135 if (ret) 136 return ret; 137 /* Disallow values lower than 2 and higher than 65535 ms */ 138 if (hw_margin < 2 || hw_margin > 65535) 139 return -EINVAL; 140 141 priv->always_running = of_property_read_bool(np, 142 "always-running"); 143 144 watchdog_set_drvdata(&priv->wdd, priv); 145 146 priv->wdd.info = &gpio_wdt_ident; 147 priv->wdd.ops = &gpio_wdt_ops; 148 priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; 149 priv->wdd.max_hw_heartbeat_ms = hw_margin; 150 priv->wdd.parent = dev; 151 priv->wdd.timeout = SOFT_TIMEOUT_DEF; 152 153 watchdog_init_timeout(&priv->wdd, 0, dev); 154 155 watchdog_stop_on_reboot(&priv->wdd); 156 157 if (priv->always_running) 158 gpio_wdt_start(&priv->wdd); 159 160 return devm_watchdog_register_device(dev, &priv->wdd); 161 } 162 163 static const struct of_device_id gpio_wdt_dt_ids[] = { 164 { .compatible = "linux,wdt-gpio", }, 165 { } 166 }; 167 MODULE_DEVICE_TABLE(of, gpio_wdt_dt_ids); 168 169 static struct platform_driver gpio_wdt_driver = { 170 .driver = { 171 .name = "gpio-wdt", 172 .of_match_table = gpio_wdt_dt_ids, 173 }, 174 .probe = gpio_wdt_probe, 175 }; 176 177 #ifdef CONFIG_GPIO_WATCHDOG_ARCH_INITCALL 178 static int __init gpio_wdt_init(void) 179 { 180 return platform_driver_register(&gpio_wdt_driver); 181 } 182 arch_initcall(gpio_wdt_init); 183 #else 184 module_platform_driver(gpio_wdt_driver); 185 #endif 186 187 MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 188 MODULE_DESCRIPTION("GPIO Watchdog"); 189 MODULE_LICENSE("GPL"); 190